AbstractQueuedSynchronizer的实现分析(下)2015-02-09 infoq 刘锟洋
前言
经过本系列的上半部分JDK1.8 AbstractQueuedSynchronizer的实现分析(上)的解读,相信很多读者已经对AbstractQueuedSynchronizer(下文简称AQS)的独占功能了然于胸,那么这次我们通过对另一个工具类:CountDownLatch的分析来解读AQS的另外一个功能:共享功能。
AQS共享功能的实现
在开始解读AQS的共享功能前,我们再重温一下CountDownLatch,CountDownLatch为java.util.concurrent包下的计数器工具类,常被用在多线程环境下,它在初始时需要指定一个计数器的大小,然后可被多个线程并发的实现减1操作,并在计数器为0后调用await方法的线程被唤醒,从而实现多线程间的协作。它在多线程环境下的基本使用方式为:
//main thread// 新建一个CountDownLatch,并指制定一个初始大小CountDownLatch countDownLatch = new CountDownLatch(3);// 调用await方法后,main线程将阻塞在这里,直到countDownLatch 中的计数为0 countDownLatch.await();System.out.println("over"); //thread1 // do something//........... //调用countDown方法,将计数减1countDownLatch.countDown(); //thread2 // do something//........... //调用countDown方法,将计数减1countDownLatch.countDown(); //thread3 // do something//........... //调用countDown方法,将计数减1countDownLatch.countDown();
注意,线程thread 1,2,3各自调用 countDown后,countDownLatch 的计数为0,await方法返回,控制台输入“over”,在此之前main thread 会一直沉睡。可以看到CountDownLatch的作用类似于一个“栏栅”,在CountDownLatch的计数为0前,调用await方法的线程将一直阻塞,直到CountDownLatch计数为0,await方法才会返回,而CountDownLatch的countDown()方法则一般由各个线程调用,实现CountDownLatch计数的减1。知道了CountDownLatch的基本使用方式,我们就从上述DEMO的第一行new CountDownLatch(3)开始,看看CountDownLatch是怎么实现的。首先,看下CountDownLatch的构造方法:

和ReentrantLock类似,CountDownLatch内部也有一个叫做Sync的内部类,同样也是用它继承了AQS。再看下Sync:

如果你看过本系列的上半部分,你对setState方法一定不会陌生,它是AQS的一个“状态位”,在不同的场景下,代表不同的含义,比如在ReentrantLock中,表示加锁的次数,在CountDownLatch中,则表示CountDownLatch的计数器的初始大小。