JUC并发编程-各种锁:公平锁,非公平锁、可重入锁、自旋锁、偏向锁、轻量级锁、重量级锁、锁升级顺序、死锁、死锁排查

21. 各种锁的理解

1)公平锁,非公平锁

在Java中,锁(Lock)是一种用于多线程同步的机制公平锁非公平锁是两种不同类型的锁。

公平锁(Fair Lock)是指线程获取锁的顺序与线程请求锁的顺序保持一致。换句话说,当多个线程同时请求一个公平锁时,锁会按照线程请求锁的顺序逐一分配锁。因此,公平锁保证了线程获取锁的公平性,在一定程度上避免了线程饥饿现象(某些线程一直无法获取到锁)。公平锁的实现通常会有比较大的性能开销

非公平锁(Unfair Lock)是指线程获取锁的顺序与线程请求锁的顺序没有必然关系多个线程同时请求一个非公平锁时,锁会先尝试将锁分配给先到达的线程,如果未成功,则进入队列等待。非公平锁的实现通常比公平锁更加高效,但可能会导致某些线程长时间等待

ReentrantLock是Java中提供的一个可重入锁(Reentrant Lock)可以作为公平锁或非公平锁使用在构造ReentrantLock对象时,可以传入一个boolean参数fair,用于指定是否使用公平锁。默认情况下,ReentrantLock是非公平锁。当fair为true时,ReentrantLock会以公平锁的方式工作;当fair为false时,ReentrantLock会以非公平锁的方式工作

使用ReentrantLock时,可以通过lock()方法获取锁,通过unlock()方法释放锁对于公平锁,锁会按照线程请求锁的顺序分配;而对于非公平锁,会尽可能地将锁分配给已经等待较久的线程无论是公平锁还是非公平锁都可以通过tryLock()方法尝试获取锁,并返回获取结果

总结起来,公平锁保证了线程获取锁的公平性,避免了线程饥饿现象;非公平锁在一定程度上提高了性能,但可能导致线程长时间等待。通过ReentrantLock可以灵活地选择使用公平锁或非公平锁

1.公平锁:非常公平,不能插队,必须先来后到

/*** Creates an instance of {@code ReentrantLock}.* This is equivalent to using {@code ReentrantLock(false)}.*/
public ReentrantLock() {sync = new NonfairSync();
}

2.非公平锁:非常不公平,允许插队,可以改变顺序

/*** Creates an instance of {@code ReentrantLock} with the* given fairness policy.** @param fair {@code true} if this lock should use a fair ordering policy*/
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}

2)可重入锁

在这里插入图片描述
可重入锁Reentrant Lock)是指同一个线程在获取锁之后可以再次获取该锁而不会被阻塞。在Java中,LockSynchronized都是可重入锁的实现方式

  1. Lock显式锁):
    Lock是Java.util.concurrent.locks包下的接口,它提供了与Synchronized类似的功能,但更灵活Lock实现了一个可重入的互斥锁。下面是一个使用Lock的示例:

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;public class LockExample {private Lock lock = new ReentrantLock();public void method1() {lock.lock();try {// 代码块1method2();} finally {lock.unlock();}}public void method2() {lock.lock();try {// 代码块2} finally {lock.unlock();}}
    }
    

    上述代码中,method1()和method2()都使用了Lock来保护临界区,而且两个方法均可以重入

  2. Synchronized隐式锁):
    SynchronizedJava语言内置的锁机制,它使用起来简单方便,但相对于Lock缺少了一些灵活性Synchronized关键字可修饰方法或代码块,它的特点是同一时间只能有一个线程获得锁,其他线程将被阻塞。下面是一个使用Synchronized的示例:

    public class SynchronizedExample {public synchronized void method1() {// 代码块1method2();}public synchronized void method2() {// 代码块2}
    }
    

    上述代码中,method1()和method2()都使用了Synchronized关键字修饰,因此它们都是可重入的

无论是Lock还是Synchronized,都支持线程的重入当一个线程进入一个使用Lock或Synchronized修饰的方法或代码块时,如果该线程已经获得了锁,它可以再次获得相同的锁而不会被阻塞。这种特性使得线程可以在同一个线程内递归地调用同步方法或访问使用同步块保护的数据,可以有效地避免死锁等问题

Synchonized 锁(同一把锁)

public class Demo01 {public static void main(String[] args) {Phone phone = new Phone();new Thread(()->{phone.sms();},"A").start();new Thread(()->{phone.sms();},"B").start();}}class Phone{public synchronized void sms(){System.out.println(Thread.currentThread().getName()+"=> sms");call();//这里也有一把锁}public synchronized void call(){System.out.println(Thread.currentThread().getName()+"=> call");}
}

Lock 锁(不一样的锁)

//lock
public class Demo02 {public static void main(String[] args) {Phone2 phone = new Phone2();new Thread(()->{phone.sms();},"A").start();new Thread(()->{phone.sms();},"B").start();}}
class Phone2{Lock lock=new ReentrantLock();public void sms(){lock.lock(); //细节:这个是两把锁,两个钥匙//lock锁必须配对,否则就会死锁在里面try {System.out.println(Thread.currentThread().getName()+"=> sms");call();//这里也有一把锁} catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}public void call(){lock.lock();try {System.out.println(Thread.currentThread().getName() + "=> call");}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}
}

注意:

  • lock锁必须配对,相当于lock和 unlock 必须数量相同
  • 在外面加的锁,也可以在里面解锁;在里面加的锁,在外面也可以解锁

3)自旋锁

自动不断地去尝试,直到成功为止
自旋锁是一种基于忙等待的锁机制它不会让线程休眠,而是在获取锁失败时,线程会不断尝试获取锁,直到获取到锁为止,这种方式避免了线程切换的开销

Java中的自旋锁可以使用AtomicBoolean类来实现通过设置和获取AtomicBoolean对象的值来表示锁的状态。当一个线程需要获取锁时,会不断循环尝试获取锁,直到成功获取锁为止

下面是一个简单的示例,展示了使用自旋锁实现的互斥访问临界区的代码:

import java.util.concurrent.atomic.AtomicBoolean;public class SpinLock {private AtomicBoolean locked = new AtomicBoolean(false);public void lock() {while (!locked.compareAndSet(false, true)) {// 自旋等待获取锁}}public void unlock() {locked.set(false);}
}

在上述代码中,locked是一个AtomicBoolean对象,用于表示锁的状态。lock()方法会不断循环尝试将locked的值由false设置为true,直到成功获取锁为止。unlock()方法则将locked的值设置为false,释放锁。

下面是一个使用自旋锁的示例:

public class SpinLockExample {private SpinLock lock = new SpinLock();private int count = 0;public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}public int getCount() {return count;}
}

在上述代码中,increment()方法会获取自旋锁,然后对count进行+1操作,最后释放锁。getCount()方法则返回count的值。

值得注意的是,自旋锁适用于临界区的代码执行时间短的情况下,如果临界区的代码执行时间长,自旋锁可能会造成CPU资源的浪费。因此,在使用自旋锁时需要根据具体的场景来确定是否适合使用自旋锁

范例

在这里插入图片描述

自己设计的锁

使用CAS设计的自旋锁

在这里插入图片描述

public class SpinlockDemo {// 默认// int 0//thread nullAtomicReference<Thread> atomicReference=new AtomicReference<>();//加锁public void myLock(){Thread thread = Thread.currentThread();System.out.println(thread.getName()+"===> mylock");//自旋锁while (!atomicReference.compareAndSet(null,thread)){System.out.println(Thread.currentThread().getName()+" ==> 自旋中~");}}//解锁public void myUnlock(){Thread thread=Thread.currentThread();System.out.println(thread.getName()+"===> myUnlock");atomicReference.compareAndSet(thread,null);}}

测试:

public class TestSpinLock {public static void main(String[] args) throws InterruptedException {ReentrantLock reentrantLock = new ReentrantLock();reentrantLock.lock();reentrantLock.unlock();//使用CAS实现自旋锁SpinlockDemo spinlockDemo=new SpinlockDemo();new Thread(()->{spinlockDemo.myLock();try {TimeUnit.SECONDS.sleep(3);} catch (Exception e) {e.printStackTrace();} finally {spinlockDemo.myUnlock();}},"t1").start();TimeUnit.SECONDS.sleep(1);new Thread(()->{spinlockDemo.myLock();try {TimeUnit.SECONDS.sleep(3);} catch (Exception e) {e.printStackTrace();} finally {spinlockDemo.myUnlock();}},"t2").start();}
}

结果:

t2必须等到t1释放锁以后,才执行

4)偏向锁

Java偏向锁是一种针对线程同步优化的机制。它通过在对象头中的mark word中存储线程ID来表示该对象是否被某个线程独占,从而避免线程竞争引起的锁争用以提高程序性能

偏向锁有以下的特点

  1. 偏向锁只针对线程的同步问题,而不是对所有对象的同步进行优化
  2. 偏向锁只有在对象的mark word为空的时候才会被启用
  3. 偏向锁是一种悲观锁,即默认认为同步资源会存在竞争,需要进行加锁操作。但在实际运行过程中,由于大部分情况下锁都不会存在竞争,因此偏向锁可以大大减少资源竞争
  4. 偏向锁会在加锁之后,将线程ID写入对象的mark word中,并将对象的线程ID设置为当前线程的ID,表示该对象已经被锁定
  5. 当其他线程尝试获取同一个对象的锁时,会检查对象的mark word中的线程ID与当前线程的ID是否相等,如果相等,则表示可以获取锁,否则需要进行锁撤销操作,升级为轻量级锁

以下是一个使用偏向锁的示例

public class BiasLockExample {private static Object lock = new Object();public static void main(String[] args) {synchronized (lock) {System.out.println("Main thread has acquired the lock");// Logic here}}
}

在上面的示例中,只有主线程能够获取到lock对象的偏向锁,其他线程在尝试获取lock对象的锁时会失败,因为偏向锁只有在mark word为空时才会被启用

总结来说,偏向锁是用来优化同步操作的机制在不存在线程竞争的情况下,可以大大减少同步操作的开销。这在单线程的情况下特别有效,但在多线程竞争的情况下效果可能会降低。因此,偏向锁适用于大多数情况下都是单线程访问的场景

5)轻量级锁

轻量级锁Java中一种基于自旋的同步机制主要用于提高多线程并发执行的性能。轻量级锁的概念是在对象头中的Mark Word中添加额外的标志位,用于表示对象是否被锁定。当一个线程尝试获取一个被轻量级锁标记的对象时,它会通过CAS原子操作尝试将对象的Mark Word替换为指向线程自身的指针,如果成功,说明该线程成功获取了锁,可以继续执行。如果CAS操作失败,说明有其他线程正在持有该对象的锁,那么当前线程就会进入自旋状态,一直在循环中等待其他线程释放锁

举个例子来解释轻量级锁的工作原理

class Counter {private int count;public synchronized void increment() {count++;}
}public class Main {public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();Thread thread1 = new Thread(() -> {for (int i = 0; i < 100000; i++) {counter.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 100000; i++) {counter.increment();}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("Final count: " + counter.getCount());}
}

在这个例子中,我们定义了一个Counter类,其中有一个用synchronized修饰的increment方法。我们创建了两个线程并分别调用increment方法对计数器进行100000次增加操作。

当线程1尝试获取Counter对象的锁时,它会发现对象的Mark Word标记为可用状态,于是通过CAS操作将Mark Word更新为指向线程1的指针。线程2也会进行类似的尝试,但是由于线程1已经获取了锁并且没有释放,所以线程2的CAS操作失败,线程2进入自旋状态。

在自旋状态中,线程2会不断检查对象的Mark Word,看是否被线程1持有锁。一旦线程1释放锁,线程2就可以通过CAS操作成功获取锁,并继续执行。这种自旋等待的方式避免了线程的阻塞和唤醒,提高了多线程并发执行的效率

需要注意的是,轻量级锁适用于对锁的竞争不激烈的情况如果锁的竞争非常激烈,那么线程在自旋状态中消耗的CPU资源会增加,反而影响性能。此时,JVM会将轻量级锁升级为重量级锁,即使用传统的互斥量来实现锁的功能

6)重量级锁

重量级锁Heavyweight Lock)是一种用于多线程环境下的同步机制。它可以保证同一时刻只有一个线程能够访问被锁定的资源,从而防止多线程并发访问时可能导致的数据不一致问题

重量级锁的实现基于操作系统提供的底层同步原语如互斥量(Mutex)或信号量(Semaphore)。它通常涉及操作系统级别的上下文切换和线程阻塞/唤醒操作,因此被称为“重量级”

重量级锁的使用场景一般是在多线程并发访问共享资源时,要保证数据的一致性和线程安全性。举例来说,考虑一个银行账户的转账操作,多个线程并发执行转账业务时,需要确保每次只有一个线程能够访问该账户,避免出现并发问题。这时可以使用重量级锁对账户对象进行加锁,以保证线程安全

下面是一个简单的Java代码示例,演示了如何使用重量级锁来保护共享资源

public class BankAccount {private int balance;public void deposit(int amount) {// 获取重量级锁synchronized (this) {balance += amount;}}public void withdraw(int amount) {// 获取重量级锁synchronized (this) {if (balance >= amount) {balance -= amount;}}}
}

在上面的代码中,deposit()withdraw() 方法都使用了 synchronized 关键字来获取重量级锁。这样,在多个线程并发执行这些方法时,每次只有一个线程能够获取锁,并且安全地访问 balance 变量。

需要注意的是,重量级锁的使用可能会导致性能问题,因为它涉及到线程的上下文切换和阻塞/唤醒操作。因此,在设计多线程程序时,应该尽量避免过多地使用重量级锁,并考虑使用更轻量级的同步机制,如乐观锁、无锁编程等

7)锁升级顺序

在Java中,锁的升级顺序是从无锁状态到偏向锁状态再到轻量级锁状态最后到重量级锁状态。具体的升级过程如下:

  1. 无锁状态当多个线程访问同一个资源时,没有任何线程持有锁,所有线程都可以自由地访问该资源

  2. 偏向锁状态当一个线程访问资源时,会在对象头中记录该线程的标识,表示该线程已经获取了锁。如果其他线程想要访问该资源,会发现该资源已经被偏向锁占用,但是由于占用锁的线程是唯一的,所以其他线程不需要竞争锁,直接进入偏向锁模式

  3. 轻量级锁状态当多个线程竞争同一个资源时,会进入轻量级锁状态。在这种状态下,会先尝试使用CAS操作来获取锁,如果成功则说明获取锁的线程可以继续执行,如果失败则表示锁被其他线程持有,那么当前线程会进入自旋等待状态,不会阻塞

  4. 重量级锁状态当自旋等待一定次数后还没有成功获取锁时,线程会进入阻塞状态,此时会将锁升级为重量级锁。在重量级锁状态下,线程会被阻塞,进入等待队列,直到获取到锁的线程释放锁

锁的升级是为了提高锁的竞争效率一开始使用偏向锁来避免多线程竞争,如果有竞争则进入轻量级锁状态进行自旋等待,如果自旋等待一定次数还没有成功获取锁,则进入重量级锁状态阻塞线程。这样的锁升级机制可以根据不同场景下的线程竞争情况来选择最适合的锁状态,以提高并发性能

8)死锁

在这里插入图片描述
死锁指两个或多个线程在互斥地持有一些资源,并且同时等待其他线程释放自己持有的资源,从而导致所有线程都无法继续执行的情况。通常情况下,死锁发生时,线程将无法继续执行,除非外部干预或者有一些特殊的机制来打破死锁

死锁通常发生在多线程环境下,具有以下四个必要条件

  1. 互斥条件至少有一个资源被线程独占,其他线程无法同时访问

  2. 请求与保持条件线程至少持有一个资源,并且请求额外的资源,但是不释放已经持有的资源

  3. 不可剥夺条件线程已经获得的资源只能由自己来释放,其他线程无法剥夺

  4. 循环等待条件存在循环等待的资源链,每个线程都在等待下一个资源,使得无法被其他线程释放

下面是一个死锁的示例

class Resource {public void doSomething() {// 这里是资源的具体操作}
}class ThreadA implements Runnable {private Resource resourceA;private Resource resourceB;public ThreadA(Resource resourceA, Resource resourceB) {this.resourceA = resourceA;this.resourceB = resourceB;}public void run() {synchronized (resourceA) {System.out.println("ThreadA got resourceA");try {Thread.sleep(1000);} catch (InterruptedException e) {}synchronized (resourceB) {System.out.println("ThreadA got resourceB");// 使用资源进行操作resourceA.doSomething();resourceB.doSomething();}}}
}class ThreadB implements Runnable {private Resource resourceA;private Resource resourceB;public ThreadB(Resource resourceA, Resource resourceB) {this.resourceA = resourceA;this.resourceB = resourceB;}public void run() {synchronized (resourceB) {System.out.println("ThreadB got resourceB");try {Thread.sleep(1000);} catch (InterruptedException e) {}synchronized (resourceA) {System.out.println("ThreadB got resourceA");// 使用资源进行操作resourceA.doSomething();resourceB.doSomething();}}}
}public class DeadlockExample {public static void main(String[] args) {Resource resourceA = new Resource();Resource resourceB = new Resource();Thread threadA = new Thread(new ThreadA(resourceA, resourceB));Thread threadB = new Thread(new ThreadB(resourceA, resourceB));threadA.start();threadB.start();}
}

在上面的例子中,有两个线程ThreadA和ThreadB分别持有资源A和资源B,并且互相等待对方释放资源。当ThreadA获取到resourceA后,需要获取resourceB才能继续执行,而ThreadB也在等待获取resourceA才能继续执行。这样就形成了一个死锁,导致两个线程都无法继续执行下去。

为了避免死锁,可以使用一些技术手段,比如避免循环等待、按照固定的顺序获取资源、使用超时机制等。另外,也可以使用工具来检测和解决死锁问题,如使用Java的线程监视工具(jstack)来查看线程的状态和调用关系,或者使用嵌入式锁检查工具(javax.management)进行死锁检测和解决

package com.ogj.lock;import java.util.concurrent.TimeUnit;public class DeadLock {public static void main(String[] args) {String lockA= "lockA";String lockB= "lockB";new Thread(new MyThread(lockA,lockB),"t1").start();new Thread(new MyThread(lockB,lockA),"t2").start();}
}class MyThread implements Runnable{private String lockA;private String lockB;public MyThread(String lockA, String lockB) {this.lockA = lockA;this.lockB = lockB;}@Overridepublic void run() {synchronized (lockA){System.out.println(Thread.currentThread().getName()+" lock"+lockA+"===>get"+lockB);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockB){System.out.println(Thread.currentThread().getName()+" lock"+lockB+"===>get"+lockA);}}}
}

陷入死锁局面

问题1:
死锁避免和死锁预防的区别
死锁预防是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而死锁避免则不那么严格的限制产生死锁的必要条件的存在,因为即使死锁的必要条件存在,也不一定发生死锁。死锁避免是在系统运行过程中注意避免死锁的最终发生

排查解决

找到项目程序的进程号

1、使用jps定位进程号,jdk的bin目录下: 有一个jps

命令:jps -l

在这里插入图片描述

2、使用jstack 进程进程号 找到死锁信息

查看对应进程的堆栈信息

在这里插入图片描述

JUC并发编程-各种锁:公平锁,非公平锁、可重入锁、自旋锁、偏向锁、轻量级锁、重量级锁、锁升级顺序、死锁、死锁排查 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/659370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

能耗在线监测系统在节能管理中的应用

上海安科瑞电气股份有限公司 胡冠楠 咨询家&#xff1a;“Acrelhgn”&#xff0c;了解更多产品资讯 摘要&#xff1a;开展能耗在线监测系统建设&#xff0c;对加强政府部门和企业节能管理中的应用前景&#xff0c;分析系统在能源消费预测分析、能效对标、节能监察、能源精细化…

React中封装大屏自适应(拉伸)仿照 vue2-scale-box

0、前言 仿照 vue2-scale-box 1、调用示例 <ScreenAutoBox width{1920} height{1080} flat{true}>{/* xxx代码 */}</ScreenAutoBox> 2、组件代码 import { CSSProperties, ReactNode, RefObject, useEffect, useRef, useState } from react//数据大屏自适应函数…

node.js与express.js创建项目以及连接数据库

搭建项目 一、技术准备 node版本&#xff1a;16.16.0 二、安装node成功后&#xff0c;安装express,命令如下&#xff1a; npm install -g express 或者&#xff1a; npm install --locationglobal express 再安装express的命令工具&#xff1a; npm install --location…

MIT6.5830 实验0

前置 本次实验使用 Golang 语言实现&#xff0c;在之前的年份中&#xff0c;都是像 cs186 那样使用 Java 实现。原因&#xff1a; Golang 语言作为现代化语言&#xff0c;简单易上手但功能强大。 使参加实验的同学有同一起跑线&#xff0c;而不是像Java那样&#xff0c;有些同…

嵌入式学习 Day15

一. 指针类型辨析 二. 传参辨析 三. 结构体 1.定义结构体 练习&#xff1a; 2. 结构体大小 8&#xff0c;12

Redis核心技术与实战【学习笔记】 - 10.浅谈CPU架构对Redis性能的影响

概述 可能很多人都认为 Redis 和 CPU 的关系简单&#xff0c;Redis 的线程在 CPU 上运行&#xff0c;CPU 快 Reids 处理请求的速度也很快。 其实&#xff0c;这种认知是片面的&#xff0c;CPU 的多核架构及多 CPU 结构&#xff0c;也会影响到 Redis 的性能。如果不了解 CPU 对…

[office] excel2010双向条形图制作 #经验分享#微信

excel2010双向条形图制作 本教程为大家介绍一下excel2010中excel2010双向条形图制作方法。 1.选中工作区域 2.点击插入-->图表,选择条形图 3.为美观可将中间竖线可去掉 4.方法是选中竖线,右击-->删除 5.接下来将图例靠上,选中图例,右击-->设置图例格式-->图例选项…

[Java 并发基础]多线程编程

文章参考&#xff1a; https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html https://juejin.cn/post/6970558076642394142 文章目录 线程的创建方式继承 Thread实现 Runnable 接口实现 Callable 接口使用 Lambda使用线程池 线程创建相关的 jdk源码Thr…

专业145+总分420+电子科技大学858信号与系统考研经验电子信息与通信

今年考研各门都相对发挥比较好&#xff0c;总分420&#xff0c;专业858信号与系统145&#xff0c;数学135顺利上岸电子科技大学&#xff0c;应群里很多学弟学妹要求&#xff0c;我总结一下自己的复习经验&#xff0c;希望可以在考研路上&#xff0c;助大家一臂之力。专业课&…

软考正式改为机考,对于考生有哪些影响?

1、报名费用可能会涨价 考虑到报名费用问题&#xff0c;软考初级考生可能会担心费用是否会涨价。需要指出的是&#xff0c;并非所有地区都会涨价&#xff0c;只有部分地区有可能涨价。 2、机考考试难度会降低吗&#xff1f; 如果实施机考&#xff0c;将是一次重大改革&#…

云计算概述(云计算类型、技术驱动力、关键技术、特征、特点、通用点、架构层次)(二)

云计算概述&#xff08;二&#xff09; &#xff08;云计算类型、技术驱动力、关键技术、特征、特点、通用点、架构层次&#xff09; 目录 零、00时光宝盒 一、云计算类型&#xff08;以服务的内容或形态来分) 二、云计算的12种技术驱动力 三、云计算的关键技术 四、云计…

Fiddler修改https请求与响应 bug修复变灰了选不了等 Fiddle对夜神模拟器抓包设置

不要修改别人的东西&#xff0c;不要修改别人的东西&#xff0c;不要修改别人的东西 只用于自己的网站&#xff0c;自己安全调试。 fiddler修改https请求 1、打到要改的请求 2、替换请求内容 3、开启捕获。操作产生请求。 4、fiddler里查看请求或响应数据 &#xff0c;确认成…

05 - 什么是路由协议

1 路由协议 路由协议&#xff08;英语&#xff1a;Routing protocol&#xff09;&#xff1a; 是一种指定数据包转送方式的网上协议。Internet网络的主要节点设备是路由器&#xff0c;路由器通过路由表来转发接收到的数据。 路由协议&#xff0c;根据转发策略进行分类&#xff…

探索智慧文旅:科技如何提升游客体验

随着科技的迅猛发展&#xff0c;智慧文旅已成为旅游业的重要发展方向。通过运用先进的信息技术&#xff0c;智慧文旅不仅改变了传统旅游业的运营模式&#xff0c;更在提升游客体验方面取得了显著成效。本文将深入探讨科技如何助力智慧文旅提升游客体验。 一、智慧文旅的兴起与…

Android开发学习-中级控件

Drawable Android把所有能够显示的图形都抽象为Drawable类(可绘制的)。 这里的图形不止是图片&#xff0c;还包括色块、画板、背景等。 包含图片在内的图形文件放在res目录的各个drawable目录下&#xff0c;其中drawable目录一般保存描述性的XML文件&#xff0c;而图片文件一…

MySQL原理(三)锁定机制(1)综述

一、介绍&#xff1a; 1、锁的本质 业务场景中存在共享资源&#xff0c;多个进程或线程需要竞争获取并处理共享资源&#xff0c;为了保证公平、可靠、结果正确等业务逻辑&#xff0c;要把并发执行的问题变为串行&#xff0c;串行时引入第三方锁当成谁有权限来操作共享资源的判…

idea/webstorm 创建Vue实例 Unresolved type Vue 处理方法

1.电脑本地安装node.js 官网下载 2. 其他: 未排除变量,前期试错(以下步骤配置了,但不确定对解决问题是否有帮助)

C# .Net Framework webapi 全局日志

1.创建一个类名字叫做CustomActionFilter.cs /// <summary>/// /// </summary>public class CustomActionFilter : System.Web.Http.Filters.ActionFilterAttribute{/// <summary>/// /// </summary>/// <param name"actionExecutedContext&q…

C++ 入门(三)— 函数

文章目录 函数简介函数返回值Void 函数&#xff08;非值返回函数&#xff09;函数参数和参数局部范围函数的声明和定义具有多个代码文件的程序 函数简介 C 程序的方式工作。当程序遇到函数调用时&#xff0c;它将在一个函数内按顺序执行语句。函数调用是告诉 CPU 中断当前函数…

AI的安全应答之道

作者&#xff1a;统信UOS技术团队 2023,随着各种大语言模型的爆发&#xff0c;整个AI生态正处于从决策式AI进化到生成式AI的进程中。各类AI模型和AI应用层出不穷&#xff0c;也随之带来了与AI相关的各类潜在风险。AI开发和使用过程中的风险防范和治理&#xff0c;成为了不可忽…