目录:
一、Synchronized
二、volatile
三、CAS(CompareAndSwap)
四、LongAdder(分段锁累加器)
五、ReentrantLock(手动锁)
六、 ReentrantReadWriteLock(读写锁)
七、 countDownLatch(倒计时,门闩)
八、 CyclicBarrier(栅栏)
九、 Phaser
十、SemaPhore(信号灯)
十一、Exchanger(交换器)
十二、 LockSupport
十三、 AQS
十四、 ThreadLocal
--------------------------------------------------------------------正文分割线--------------------------------------------
一、Synchronized
1、Synchronized作用:
①同步性:保证在同一时刻,只有一个线程可以执行某个方法或某个代码块;
②可见性:保证共享对象被一个线程改变时,其他线程都立即可见。
2、Synchronized特点
①对象锁(静态方法的锁加在x.class对象上),本质是加在对象头的两位。
②互斥锁
③可重入锁:某个线程已经获得某个锁,可以再次获取锁(同步方法调锁住同一个对象的方法或者父类同步方法时)
④不公平锁:多个线程获取锁的顺序并不按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁
3、使用Synchronized可能出现的问题
①脏读:当写数据加锁,但是读数据不加锁;
②死锁:多个线程要访问的资源互相被占用造成程序无法进行下去的情况;
③锁的引用发生变化(所以用final修饰)导致锁无效;
④使用字符串或者基础类型数据作为锁(可能会死锁或不可知情况);
⑤线程中抛异常时会释放锁(所以需要try catch中小心处理异常);
4、Synchronized同步优化
①细化锁的颗粒度(针对锁住的代码块过多);
②粗化锁的颗粒度(针对代码块中多个地方加锁);
③使用Atomicxxx原子类(无锁优化CAS);
5、底层实现同步原理
在进入同步代码之前先获取锁,获取到锁之后锁的计数器+1,同步代码执行完锁的计数器-1,如果获取失败就阻塞式等待锁的释放。
同步方法通过ACC_SYNCHRONIZED标志,同步代码块是monitorenter和monitorexit指令操作。
6、Synchronized锁的四种状态和升级(单向升级,不可降级)
①无锁状态;
②偏向锁状态(第一个线程访问,只记录线程ID);
③轻量级锁状态(如果有线程争用则升级为轻量级锁,获取锁失败则进入自旋,旋转10次后升级为重量级锁,轻量级锁占用CPU);
④重量级锁(需要申请操作系统资源,但是不占用CPU,效率低)
7、底层实现可见性原理
JMM关于synchronized的两条规定:
1)线程解锁前,必须把共享变量的最新值刷新到主内存中
2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值。
8、自旋锁和重量级锁的适用情况
自旋锁:线程执行时间短,线程数少(Atomicxxx,各种Lock)
重量级锁:线程执行时间长,线程数多
二、volatile
1、volatile作用:
①可见性:保证共享对象被一个线程改变时,其他线程都立即可见(MESI:cpu缓存一致性协议);
②有序性:禁止指令重排序。
2、Volatile特点:
①效率比synchronised高;
②不能保证同步。
3、volatile如何保证有序性(禁止指令重排序)?
添加四个内存屏障

4、MESI缓存一致性协议?
CPU中每个缓存行(caceh line)使用4种状态进行标记(使用额外的两位(bit)表示):
M: 被修改(Modified)
该缓存行只被缓存在该CPU的缓存中,并且是被修改过的(dirty),即与主存中的数据不一致,该缓存行中的内存需要在未来的某个时间点(允许其它CPU读取请主存中相应内存之前)写回(write back)主存。
当被写回主存之后,该缓存行的状态会变成独享(exclusive)状态。
E: 独享的(Exclusive)
该缓存行只被缓存在该CPU的缓存中,它是未被修改过的(clean),与主存中数据一致。该状态可以在任何时刻当有其它CPU读取该内存时变成共享状态(shared)。
同样地,当CPU修改该缓存行中内容时,该状态可以变成Modified状态。
S: 共享的(Shared)
该状态意味着该缓存行可能被多个CPU缓存,并且各个缓存中的数据与主存数据一致(clean),当有一个CPU修改该缓存行中,其它CPU中该缓存行可以被作废(变成无效状态(Invalid))。
I: 无效的(Invalid)
该缓存是无效的(可能有其它CPU修改了该缓存行)。

5、可能出的问题
修饰引用类型时,引用指向的对象内容变化,volatile可能不起作用;
三、CAS(CompareAndSwap)
1、CAS内容:
CAS需要有3个操作数:内存地址V,旧的预期值old,即将要更新的目标值new。
CAS指令执行时,当且仅当内存地址V的值与预期值old相等时,将内存地址V的值修改为new,否则就什么都不做。并且Cpu保证整个比较并替换的操作是一个原子操作。
2、CAS缺点:
1)循环时间长开销很大。
2)只能保证一个共享变量的原子操作。
3)ABA问题(Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效)。
四、LongAdder(分段锁累加器)
1、longAdder原理:
longAdder将value分散到一个数组中不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作。
2、longAdder性能:
longAdder在并发非常大时效率高于AtomicLong,但是也占用内存(以空间换时间)。
五、ReentrantLock(手动锁)
1、ReentrantLock作用:
手动给代码块加同步锁。
①可见性:保证共享对象被一个线程改变时,其他线程都立即可见(MESI:cpu缓存一致性协议);
②同步性;
2、ReentrantLock如何保证可见性
ReentrantLock的同步其实是委托给AbstractQueuedSynchronizer的。加锁和解锁是通过改变AbstractQueuedSynchronizer的state属性,这个属性是volatile的,volatile也能保证可见性
3、ReentrantLock与synchronised不同
①ReentrantLock必须手动加锁(lock())手动解锁(unlock);
②ReentrantLock可以尝试锁定;
③ReentrantLock可以指定公平锁和非公平锁(默认);
④ReentrantLock可以被interrupt打断
六、 ReentrantReadWriteLock(读写锁)
1、ReadWriteLock作用:
允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。即写数据时使用排它锁,读锁可以在没有写锁的时候被多个线程同时持有(共享锁)。
2、使用场景:
假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。
七、 countDownLatch(倒计时,门闩)
1、countDownLatch作用:
能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行(线程间通讯)。
2、主要方法:
Countdown() await()
八、 CyclicBarrier(栅栏)
1、CyclicBarrier作用:
能阻塞一组线程直到指定的线程数必须同时到达栅栏位置,才能继续执行(线程间通讯)。
3、主要方法:
new CyclicBarrier(20, () -> System.out.println("。。。")) await()
九、 Phaser
1、phoser作用:
控制多个线程分阶段共同完成任务(线程间通讯)。
十、*SemaPhore(信号灯)
1、semaPhore作用:
同一时刻允许多少个线程运行(线程间通讯)。
acquire(获取锁,阻塞方法,将信号数量减1)
release(释放灯信号,信号数量加1)
2、semaPhore场景:
限流
十一、Exchanger(交换器)
1、作用:用于两个工作线程之间交换数据(线程间通讯);
2、主要方法
①exchange(s)阻塞线程,等待另一个线程
3、场景:游戏中交换武器装备
十二、 LockSupport
1、作用:
阻塞或者唤醒一个线程(线程间通讯)
2、主要方法
Park() unpark()
3、特点
①无需加锁
②可精确唤醒某个线程
③unpark可于park之前执行;
十三、 AQS

AQS维护了一个volatile的state和一个线程队列
使用了varHandle--->>1普遍属性原子操作 2比反射快,直接操纵二进制码
十四、 ThreadLocal
线程独有的局部变量
原理:将对象放在了当前线程实例的Map<ThreadLocal,Object>中
场景:声明式事务,保证同一个Connection
网友评论