ReentrantLock,互斥锁,重入锁
ReentrantLock,互斥锁,重入锁 在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确保在某一时刻,方法内只允许有一个线程。 synchronized 采用 synchronized 修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个 monitor (锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。 这里就使用同步机制获取互斥锁的情况,进行几点说明: 如果同一个方法内同时有两个或更多线程,则每个线程有自己的局部变量拷贝。 类的每个实例都有自己的对象级别锁。当一个线程访问实例对象中的 synchronized 同步代码块或同步方法时,该线程便获取了该实例的对象级别锁,其他线程这时如果要访问 synchronized 同步代码块或同步方法,便需要阻塞等待,直到前面的线程从同步代码块或方法中退出,释放掉了该对象级别锁。 访问同一个类的不同实例对象中的同步代码块,不存在阻塞等待获取对象锁的问题,因为它们获取的是各自实例的对象级别锁,相互之间没有影响。 持有一个对象级别锁不会阻止该线程被交换出来,也不会阻塞其他线程访问同一示例对象中的非synchronized代码。当一个线程A持有一个对象级别锁 (即进入了 synchronized 修饰的代码块或方法中) 时,线程也有可能被交换出去,此时线程B有可能获取执行该对象中代码的时间,但它只能执行非同步代码 (没有用synchronized修饰) ,当执行到同步代码时,便会被阻塞,此时可能线程规划器又让A线程运行,A线程继续持有对象级别锁,当A线程退出同步代码时 (即释放了对象级别锁) ,如果B线程此时再运行,便会获得该对象级别锁,从而执行synchronized中的代码。 持有对象级别锁的线程会让其他线程阻塞在所有的 synchronized 代码外。例如,在一个类中有三个synchronized方法 a,b,c,当线程A正在执行一个实例对象M中的方法 a 时,它便获得了该对象级别锁,那么其他的线程在执行同一实例对象 (即对象M) 中的代码时,便会在所有的 synchronized 方法处阻塞,即在方法 a,b,c处都要被阻塞,等线程A释放掉对象级别锁时,其他的线程才可以去执行方法a,b或者c中的代码,从而获得该对象级别锁。 使用 synchronized (obj) 同步语句块,可以获取指定对象上的对象级别锁。obj为对象的引用,如果获取了obj对象上的对象级别锁,在并发访问obj对象时时,便会在其synchronized代码处阻塞等待,直到获取到该obj对象的对象级别锁。当obj为 this 时,便是获取当前对象的对象级别锁。 类级别锁被特定类的所有示例共享,它用于控制对static成员变量以及static方法的并发访问。具体用法与对象级别锁相似。 互斥是实现同步的一种手段,临界区、互斥量和信号量都是主要的互斥实现方式. synchronized 关键字经过编译后,会在同步块的前后分别形成 monitorenter 和 monitorexit 这两个字节码指令。根据虚拟机规范的要求,在执行 monitorenter 指令时,首先要尝试获取对象的锁,如果获得了锁,把锁的计数器加1,相应地,在执行 monitorexit 指令时会将锁计数器减1,当计数器为0时,锁便被释放了。由于synchronized 同步块对同一个线程是可重入的,因此一个线程可以多次获得同一个对象的互斥锁,同样,要释放相应次数的该互斥锁,才能最终释放掉该锁。 synchronized 是非公平锁 (TODO: 需要测试,没重现成功…) https://blog.csdn.net/FU250/article/details/106640613 ReentrantLock ReentrantLock 是一个可重入的互斥锁,又被称为"独占锁"。ReentrantLock 的实现不仅可以替代隐式的 synchronized 关键字,而且能够提供超过关键字本身的多种功能。 而锁的名字也是说明了这个锁具备了重复进入的可能,也就是说能够让当前线程多次的进行对锁的获取操作,这样的最大次数限制是 Integer.MAX_VALUE,约 21 亿次左右。 ...