重入锁可以看成synchronized的增强版,可以完全替代synchronized关键字,可以使用JUC下的locks.ReentrantLock类实现。从命名可以看出,重入锁可以反复进入,使用中比较灵活,开发人员可以手动指定何时加锁,何时释放锁,对逻辑的控制远超过关键字synchronized,唯一值的注意的是,退出临界区必须要释放锁,否则,其他线程就没有机会再访问临界区。
重入锁:可以提供中断响应,对于synchronized关键字,如果一个线程等待锁,要么获得锁继续执行,要么保持等待。但使用重入锁:
(1)可以使得线程中断。如果一个线程正在等待锁,它依然可以收到一个通知,被告知无需等待,可以停止,这对解决死锁还是有一定帮助的。
(2)限时等待,给定一个等待时间,让程序自动放弃。ReentrantLock.tryLock()方法可以带参数,就是等待一定时间,如果超过设定时间还没有获得锁就返回false,也可以不带参数,当前线程立即尝试获得锁,如果成功返回true,否则返回false。
(3)重入锁可以设置公平锁,顾名思义,多个线程请求锁时会按照发送请求的先后顺序来分配。构造函数:
public ReentrantLocal(boolean fair)
重入锁的好搭档:Condition
Condition对象与wait()和notify()方法大致相同,利用Condition对象可以让线程在合适的时间等待,或者在某一个特定的时刻得到通知。
Condition接口主要提供的方法有:
await()方法,使当前线程等待,同时释放当前锁,当使用signal()方法时,线程会重新获得锁继续执行(在signal()和await()方法执行前,线程必须拥有锁)。
读写锁
ReadWriteLock是JDK1.5提供的,读写分离锁可以有效的减少竞争,提高系统性能。在系统中,读操作的次数远远大于写的操作次数,读写锁可以发挥很大功能
倒计数器:
CountDownLatch:主要是用来控制线程等待,可以让某一个线程等待直到倒计数结束,再开始执行。
public CountDownLatch(int count)
参数即为当前计数器的计数个数。
public class CountDownLatchDemo implements Runnable {
static CountDownLatch end = new CountDownLatch(10);
static CountDownLatchDemo demo = new CountDownLatchDemo();
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10)*1000);
System.out.println("check complete");
end.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
//两种写法
public static void main(String[] args) throws Exception{
// ExecutorService exec = Executors.newFixedThreadPool(10);
// for(int i=0;i<10;i++){
// exec.submit(demo);
// }
Thread[] threads = new Thread[10];
for(int i=0;i<10;i++){
threads[i] = new Thread(demo,"thread"+i);
threads[i].start();
}
end.await();
System.out.println("fire");
// exec.shutdown();
}
}
主线程在CountDownLatch上等待,当所有的检查任务都完成后,主线程继续。
循环栅栏
CyclicBarrier也是一种线程并发控制工具,也可以实现线程间的计数等待。比CountDownLatch功能强大一些,可以接收一个参数作为barrierAction。所谓barrierAction就是当计数器一次计数完成后,系统会执行的动作。
public class CyclicbarrierDemo {
public static class Soldier implements Runnable{
private String soldier;
private final CyclicBarrier cyclicBarrier;
Soldier(CyclicBarrier cyclicBarrier,String soldierName){
this.cyclicBarrier =cyclicBarrier;
this.soldier = soldierName;
}
@Override
public void run() {
try {
//等待所有士兵到齐
cyclicBarrier.await();
doWork();
//等待所有士兵完成工作
cyclicBarrier.await();
}catch (Exception e){
e.printStackTrace();
}
}
void doWork(){
try {
Thread.sleep(Math.abs(new Random().nextInt()%10000));
}catch (Exception e){
e.printStackTrace();
}
System.out.println(soldier+":完成任务");
}
}
public static class BarrierRun implements Runnable{
boolean flag;
int N;
public BarrierRun(boolean flag, int N){
this.flag = flag;
this.N = N;
}
@Override
public void run() {
if(flag){
System.out.println("司令:[士兵"+N+"个,完成任务");
}else {
System.out.println("司令:[士兵"+N+"个,集合完毕");
flag = true;
}
}
}
public static void main(String[] args) {
final int N = 10;
Thread[] allSoldier = new Thread[N];
boolean flag = false;
CyclicBarrier cyclicBarrier = new CyclicBarrier(N,new BarrierRun(flag,N));
System.out.println("集合队伍");
for(int i=0;i<N;++i){
System.out.println("士兵"+i+"报道");
allSoldier[i] = new Thread(new Soldier(cyclicBarrier,"士兵"+i));
allSoldier[i].start();
}
}
}