第三节:Atomic类和线程同步新机制
一、atomic类
- 说明:
- 此类中的所有类型都使用了CAS自旋锁,达到原子性
- 属于一种无锁优化,因此要比synchronized锁要轻
- 对Long数据进行递增的三种方式
- synchronized+volatie
- AtomicLong
- LongAdder
- 以上三种从上自下,效率越高
- 为什么Atomic要比synchronized快?
- 因为Atomic其底层使用的无锁CAS,轻量级锁进行原子性操作;而synchronized会进行锁升级,当某种情况会向操作系统申请重量级锁,所以有时候Atomic要比synchronized的效率高
- 为什么LongAdder要比Atomic的效率高?(有待后续继续代码求证)
- 因为LongAdder中使用的分段锁
- 它会将所有线程平均分布在一个数组中
- 每个数组元素都会有需要递增的那个变量
- 每个元素中的线程对其进行递增完毕后
- 它会将每个元素中递增完毕的变量值进行求sum
二、基于CAS的几种新类型锁
-
ReentrantLock
-
特点:
-
可重入
-
默认非公平锁,可以指定为公平锁
-
-
可替换synchronized锁
- 在需要加锁的逻辑前加锁lock.lock()
- 但必须在try…finally中进行手动解锁lock.unlock()
-
ReentrantLock和synchronized
- ReentrantLock和synchronized都是可重入锁
- synchronized解锁会由jvm进行解锁
- ReentrantLock解锁必须手动解锁,否则会造成死锁
-
为什么ReentrantLock和synchronized差不多,还需要ReentrantLock
- 因为ReentrantLock中的功能要比synchronized多
-
ReentrantLock常见方法:
- tryLock():进行尝试加锁,会返回一个布尔值,但不管锁定与否,方法都会被执行;synchronized抢到不到,就会进行阻塞
- lockInterruptibly:后续自己去学习下
-
-
CountDownLatch
- 解释:CountDown:倒数,Latch:门闩(倒数的一个门闩5,4,3,2,1,0数到了,这个门闩就会被打开)
- latch.countDown():每条线程完成逻辑后,操作此方法,对门闩进行减一;
- latch.wait():每条线程线程执行完自己的逻辑后并操作完latch.countDown,会被阻塞在latch.wait中,直至latch.countDown初始化的门闩数减至0,latch.wait才会放开,线程才会结束;
-
Cyclicbarrier
- 解释:循环栅栏,这有个栅栏,什么时候人满了就把栅栏推到,哗啦哗啦的都放出去,出去之后栅栏又重新关起来,满了,再放以此循环
- 主要方法:
- new Cyclicbarrier(20)或者new Cyclicbarrier(20,()->{sout(“满人”);}),两个new都是设置了满20人才会放开,第二个参数为放开后需要执行的逻辑,没有则就是不做任何处理
- barrier.await()方法:线程等待,直到满指定数量后,才会放开
-
Phaser
- 解释:结合了CountDownLatch和Cyclicbarrier的一个名叫阶段,分阶段的栅栏
- 按照不同的节点来对线程进行执行,每个阶段不同的时候这个线程都可以往前走,有的线程走到某个阶段就停了,有的线程一直会走到结束
-
ReadWriteLock
- 读写锁:共享锁和排他锁,读锁是共享锁,写锁是排他锁
- ReentrantReadWriteLock是ReadWriteLock的一个实现类
- 作用:
- 对读操作的效率提升
-
以后还写不写synchronized?分布式锁咋实现?
- 多数情况使用synchronized
- 特别追求效率,再去使用其他新锁
- 分布式锁:redis分布式锁(两种方式,redis是单线程的),zookeeper分布式锁,数据库分布锁(效率较低)
-
Semaphore
- 解释:信号灯,含义限流,有几个信号灯,就允许几个线程通过
- 常见方法:
- acquire():阻塞方法,每个线程去acquire(得到)一个信号灯,则可以通过,得不到则阻塞
- release():释放方法,得到信号灯的线程,执行完,进行释放信号灯
- 作用:
- 可以起到限流作用,多个请求进来,只有拿到信号灯的请求才能进入,没有拿到的就会阻塞
- 特点:
- 默认非公平锁
- 有参构造可以改成公平锁
-
Exchanger
- 解释:交换器,两人之间互相交换个数据用的
- 场景:
- 只能在两个线程之间,进行交换,只需要互相操作Exchanger对象中的exchange(交换的参数)方法进行交换
-
AQS
- 基于CAS的几种新类型锁使用的都是同一个队列,同一个类来实现的,这个类叫AQS
-
</