理解AQS(AbstractQueuedSynchronizer)
可重入锁又名递归锁:是指在同一线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁对象得是同一个对象),不会因为之前已经获取过还没释放而阻塞。
Java中ReentrantLock和synchranized都是可重入锁,可重入锁得一个优点是可一定程度避免死锁
synchronized的重入的实现原理:
每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。当执行monitorenter时,如果目标锁对象的计数器为零,那么说明它没有被其他线程所持有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将其计数器加1。
在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么java虚拟机可以将其计数器加1,否则需要等待,直至持有线程释放该锁。
当执行monitorexit时,java虚拟机则需将锁对象的计数器减1。计数器为零代表锁已被释放。
唤醒线程的三种方式:

Object类中的wait、notify、notifyAll用于线程等待和环形的方法,都必须在synchronized内部执行(必须用到关键字synchronized)
public class LockSupportDemo { static Object objectlock=new Object(); public static void main(String[] args) { new Thread(()->{ synchronized (objectlock){ System.out.println(Thread.currentThread().getName()+"\t"+"--------come in"); try { objectlock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"\t"+"--------被唤醒"); } },"A").start(); new Thread(()->{ synchronized (objectlock) { objectlock.notify(); System.out.println(Thread.currentThread().getName()+"\t"+"--------通知"); } },"B").start(); } }
传统的synchronized和Lock实现等待唤醒通知的约束,线程先要获得并持有锁,必须在块(synchronized或lock)中,必须要先等待后唤醒,线程才能够被唤醒
public static void lockAwaitSignal() { new Thread(()->{ lock.lock(); try { System.out.println(Thread.currentThread().getName()+"\t"+"--------come in"); try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"\t"+"--------被唤醒"); }finally { lock.unlock(); } },"A").start(); new Thread(()->{ lock.lock(); try { condition.signal(); System.out.println(Thread.currentThread().getName()+"\t"+"--------通知"); }finally { lock.unlock(); } },"B").start(); }
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对象的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码。
LockSupport提供park()和unpark()方法实现阻塞线程和解除线程阻塞的过程
LockSupport和每个使用它的线程都有一个许可(permit)关联。permit相当于1,0的开关,默认是0,调用一次unpack就加1变成1,调用一个park会消费permit,也就是将1变成0,同时park立即返回,如再次调用park会变成阻塞(因为permit为零了会阻塞在这里,一直到permit变为1),这时调用unpark会把permit置为1,每个线程都有一个相关的permit,permit最多只有一个,重复调用unpark也不会积累凭证
AQS是用来构建锁(ReentrantLock)或者其它同步器组件(semaphore、countdownlatch等)的重量级基础框架及整个JUC体系的基石,通过内置的FIFO队列来完成资源获取线程的排队工作,并通过一个int类型变量表示持有锁的状态

浙公网安备 33010602011771号