接并发编程1
synchronized锁的实现
通过底层指令控制实现,Java提供的一种原子性内置锁,在进入synchronized后会从主内存复制一份共享变量到自己的工作内存,在工作内存中修改完成后,退出时会把工作内存的值写入到主内存,保证原子性。
synchronized基于进入和退出监视器对象来实现方法同步和代码块同步。
同步方法使用ACC_SYNCHRONIZED标记是否是同步方法,方法调用时,先检测该方法是不是同步的,如果是,进入方法时需要monitorenter,退出时monitorexxit。
monitorenter 检测锁
monitorexxit 释放锁
代码块的同步是利用 monitorenter 和 monitorexit 这两个字节码指令。在虚拟机执行到 monitorenter 指令时,首先要尝试获取对象的锁。当前线程拥有了这个对象的锁,把锁的计数器+1;当执行 monitorexit 指令时将模计数器-1;当计数器为 0 时,锁就被释放了。
synchronized通过在对线头设置标记,来实现获取锁和释放锁。
AQS(AbstractQueuedynchronizer)
抽象同步队列
AQS是一个用来构建锁和同步器的框架,是JUC中的核心组件,,常见的ReentrantLock,CountDownLatch等都是基于AQS实现的。
AQS实现原理
在AQS类的内部有一个state变量表示锁是否被使用,初始化为0,在多线程情况下,线程要执行临界区代码,首先要获取state,获取成功后state+1,其他线程正在获取时由于共享资源已被占用,会进入一个双端队列FIFO等待,等占有state的线程执行完临界区的代码释放资源后state-1,会唤醒FIFO中的下一个等待的线程(head的下一个节点)去获取state。
AbstractQueuedynchronizer成员
private transient volatile Node head;
private transient volatile Node tail;
/*使用变量 state 表示锁状态,0-锁未被使用,大于 0 锁已被使用
共享变量 state,使用 volatile 修饰保证线程可见性
*/
private volatile int state;
protected final int getState() { //获得锁状态
return state;
}
//使用 CAS 机制设置状态
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
ReentrantLock锁实现(互斥锁)
是JUC包下的类,实现了Lock接口,提供了与SYNCHRONIZED不同的另一种同步操作方式,更加灵活。
基于AQS,在并发编程中可以实现公平锁与非公平锁来对资源进行同步。首先 AQS 中的 state 为 0.
A 线程在执行 lock() 方法后,以独占方式 CAS state 为 1。AQS 会记录 A 线程为当前的独占线程,其他线程如果再尝试获取资源,就会进入等待队列,直到 A 线程调用 unlock() 方法,释放了资源,即 state 回归 0 状态。
在“重入性”方面,如果A线程第二次尝试取锁,state 会累加。也就是说,上锁的次数一定等于释放锁的次数。
CountDownLatch(共享锁)
底层实现是通过AQS来完成的。
CountDownLatch 允许一个线程等待其他线程各自执行完毕后再执行,可以延迟线程的进度直到终止状态。与 ReentrantLock 不同的是,在构造 CountDownLatch 对象的时候,会先设定一个 state 大小:
JUC常用类
ConcurrentHashMap
是一个线程安全的哈希表,对于多线程的操作,结余HashMap与Hashtable之间,内部采用“锁分段”机制。
放弃分段锁的原因:
1.加入多个分段锁浪费内存空间
2.map再放入时竞争一个锁的概率很小,分段锁反而会造成更新操作的长时间等待。
jdk8后采用Node锁,减小锁的粒度,提高性能,使用CAS操作来保证原子性。
实现原理

CopyOnWriteArrayList
原理:
CopyOnWriteArraySet
基于CopyOnWriteArrayList实现,不能存储重复数据。
文章参考:一文搞懂到底什么是 AQS
Java 多线程 —— AQS 详解