在写并发代码来提升性能时,会遵循某些最佳写法,而不是只用基础的wait和notify来控制复杂的流程。
Java.util.concurrent 包是专为 Java并发编程而设计的包,它下有很多编写好的工具,使用这些更高等的同步工具来编写代码,让我们的程序可以不费力气就得到优化。这些工具还在由一些优秀的工程师不断优化和完善,我们不必重复造轮子:
这篇文章讲述思维导图的工具类部分:
- ReentrantLock
- Condition
- Semaphore
- ReentrantReadWriteLock
- CountDownLatch
- CyclicBarrrer
1.ReentrantLock
1.1可重入
单线程可以重复进入,但必须重复退出。
一个线程拿到几个许可,就得释放几次,不然就造成线程等待,可在命令行查看等待的线程:jps -->jstack [ option ] pid
1.2可中断
长期线程在锁上等待问题,可以通过中断来解决:
可在命令行查看死锁:jps -->jstack [ option ] pid
1.3可限时
可限时也是一个避免永久等待构成死锁的解决方法:
1.4公平锁
先来的线程先得到锁,如果先来的线程一直拿不到锁,则会产生饥饿现象,公平锁虽然不会产生饥饿现象,排队会导致程序效率差。通过阅读ReentrantLock的源码发现:默认是非公平的,如果传入true,则是公平锁:
2.Condition
Condition与ReentrantLock的关系就类似于synchronized与Object.wait()/notify()。但是它与ReentrantLock结合使用,有await和signal与之对应.
利用Condition实现顺序执行:
3.Semaphore
翻译为信号量,允许多个线程进入临界区。说白了就是一个广义上的锁,相当于共享锁。比如信号量中我可以给它指定10个许可,每一个许可可以分配给若干个线程(当然一个线程也可以拿多个许可),拿到许可线程可以执行,如果许可分发完了,后面的线程就和锁一样去做等待。换句话说,当信号量等于1的时候,就相当于一把锁。
比如早期做限流时,我们系统是8核cpu,设置同时请求任务为8个,超过8个,可以用信号量让线程等待来加以控制:
4.ReentrantReadWriteLock
ReentrantReadWriteLock,首先要做的是与ReentrantLock划清界限, 它和后者都是单独的实现,彼此之间没有继承或实现的关系。读写锁可以很好的提高程序效率,如果读也加锁的话,每次只有一个线程能访问,不符合高并发程序设计。ReentrantLock和synchronized都属于阻塞的并行,会把线程挂起,而ReadWriteLock属于无等待的并发。
访问情况:读读共享,读写互斥,写写互斥
5.CountDownLatch
实际开发中经常用于监听某些初始化操作,等待初始化完成后,通知主线程继续工作,它相当于一个栅栏
测试代码:
6.CyclicBarrrer
倒数计时器。假设有一个场景:每个线程代表一个跑步运动员,当运动员都准备好后,才能一起出发,只要有一个人没有准备好,大家都等待:
系列:
【JDK并发包基础】线程池详解
【JDK并发包基础】并发容器详解
【JDK并发包基础】工具类详解
閱讀更多 Java是最好的語言NO1 的文章