AQS解读及相关AQS实现类
1. AQS概述
简述:AQS全称AbstractQueuedSynchronizer,即抽象队列同步器。AQS是用来构建锁或者其他同步组件的基础框架,它使用一个整型的volatile变量state来维护同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。AQS为一系列同步器依赖于一个单独的原子变量state的同步器提供了一个非常有用的基础。
AQS的设计是基于模板方法模式设计的,子类通过继承AQS并实现它的抽象模板方法来管理同步状态,而这些模板方法内部就是真正管理同步状态的地方(主要有tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared等)。
AQS既可以支持独占锁地,也支持共享锁,这样就可以方便实现不同类型的同步组件如ReentrantLock、ReentrantReadWriteLock和CountDownLatch等。
AQS类使用单个int(32位)来保存同步状态,并暴露出getState、setState以及compareAndSet操作来读取和更新这个同步状态。其中属性state被声明为volatile,并且通过使用CAS指令来实现compareAndSetState,使得当且仅当同步状态拥有一个一致的期望值的时候,才会被原子地设置成新值,这样就达到了同步状态的原子性管理,确保了同步状态的原子性、可见性和有序性。
AQS简单推导流程:
1.根据ReentrantLock、ReentrantReadWriteLock实现推导,深入理解JAVA中的锁那节,讲到了ReentrantLock、ReentrantReadWriteLock的实现原理,他们都有共同的特性,owner(锁持有者)、writecount(重入次数)、waiters(等待队列),简单的AQS即是提出公共的代码,提供必要的实现类,实现不同的锁功能。
2.先看自己实现的ReentrantLock、ReentrantReadWriteLock的代码
ReentrantLock:
package com.study.lock.locks1;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
public class JamesReentrantLock implements Lock {
//标记重入次数的count值
AtomicInteger count = new AtomicInteger(0);
//锁的拥有者
AtomicReference<Thread> owner = new AtomicReference<>();
//等待队列
private LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();
@Override
public boolean tryLock() {
//判断count是否为0,若count!=0,说明锁被占用
int ct = count.get();
if (ct !=0 ){
//判断锁是否被当前线程占用,若被当前线程占用,做重入操作,count+=1
if (owner.get() == Thread.currentThread()){
count.set(ct + 1);
return true;
}else{
//若不是当前线程占用,互斥,抢锁失败,return false
return false;
}
}else{
//若count=0, 说明锁未被占用,通过CAS(0,1) 来抢锁
if (count.compareAndSet(ct, ct +1)){
//若抢锁成功,设置owner为当前线程的引用
owner.set(Thread.currentThread());
return true;
}else{
//CAS操作失败,说明情锁失败 返回false
return false;
}
}
}
@Override
public void lock() {
//尝试抢锁
if (!tryLock()){
//如果失败,进入等待队列
waiters.offer(Thread.currentThread());
//自旋
for (;;){
//判断是否是队列头部,如果是
Thread head = waiters.peek();
if (head == Thread.currentThread()){
//再次尝试抢锁
if (!tryLock()){
//若抢锁失败,挂起线程,继续等待
LockSupport.park();
}else{
//若成功,就出队列
waiters.poll();
return;
}
}else{
//如果不是,就挂起线程
LockSupport.park();
}
}
}
}
@Override
public void unlock() {
if (tryUnlock()){
Thread th = waiters.peek();
if (th !=null){
LockSupport.unpark(th);
}
}
}
public boolean tryUnlock(){
//判断,是否是当前线程占有锁,若不是,抛异常
if (owner.get() != Thread.currentThread()){
throw new IllegalMonitorStateException();
}else{
//如果是,就将count-1 若count变为0 ,则解锁成功
int ct = count.get();
int nextc = ct-1;
count.set(nextc);
//判断count值是否为0
if (nextc == 0){
owner.compareAndSet(Thread.currentThread(), null);
return true;
}else{
return false;
}
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
}
ReentrantReadWriteLock:
package com.study.lock.locks1;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
public class JamesReadWriteLock {
volatile AtomicInteger readCount = new AtomicInteger(0);
AtomicInteger writeCount = new AtomicInteger(0);
//独占锁 拥有者
AtomicReference<Thread> owner = new AtomicReference<>();
//等待队列
public volatile LinkedBlockingQueue<WaitNode> waiters = new LinkedBlockingQueue<WaitNode>();
class WaitNode{
int type = 0; //0 为想获取独占锁的线程, 1为想获取共享锁的线程
Thread thread = null;
int arg = 0;
public WaitNode(Thread thread, int type, int arg){
this.thread = thread;
this.type = type;
this.arg = arg;
}
}
//获取独占锁
public void lock() {
int arg = 1;
//尝试获取独占锁,若成功,退出方法, 若失败...
if (!tryLock(arg)){
//标记为独占锁
WaitNode waitNode = new WaitNode(Thread.currentThread(), 0, arg);
waiters.offer(waitNode); //进入等待队列
//循环尝试拿锁
for(;;){
//若队列头部是当前线程
WaitNode head = waiters.peek();
if (head!=null && head.thread == Thread.currentThread()){
if (!tryLock(arg)){ //再次尝试获取 独占锁
LockSupport.park(); //若失败,挂起线程
} else{ //若成功获取
waiters.poll(); // 将当前线程从队列头部移除
return; //并退出方法
}
}else{ //若不是队列头部元素
LockSupport.park(); //将当前线程挂起
}
}
}
}
//释放独占锁
public boolean unlock() {
int arg = 1;
//尝试释放独占锁 若失败返回true,若失败...
if(tryUnlock(arg)){
WaitNode next = waiters.peek(); //取出队列头部的元素
if (next !=null){
Thread th = next.thread;
LockSupport.unpark(th); //唤醒队列头部的线程
}
return true; //返回true
}
return false;
}
//尝试获取独占锁
public boolean tryLock(int acquires) {
//如果read count !=0 返回false
if (readCount.get() !=0)
return false;
int wct = writeCount.get(); //拿到 独占锁 当前状态
if (wct==0){
if (writeCount.compareAndSet(wct, wct + acquires)){ //通过修改state来抢锁
owner.set(Thread.currentThread()); // 抢到锁后,直接修改owner为当前线程
return true;
}
}else if (owner.get() == Thread.currentThread()){
writeCount.set(wct + acquires); //修改count值
return true;
}
return false;
}
//尝试释放独占锁
public boolean tryUnlock(int releases) {
//若当前线程没有 持有独占锁
if(owner.get()!= Thread.currentThread()){
throw new IllegalMonitorStateException(); //抛IllegalMonitorStateException
}
int wc= writeCount.get();
int nextc = wc - releases; //计算 独占锁剩余占用
writeCount.set(nextc); //不管是否完全释放,都更新count值
if (nextc==0){ //是否完全释放
owner.compareAndSet(Thread.currentThread(), null);
return true;
}else{
return false;
}
}
//获取共享锁
public void lockShared() {
int arg = 1;
if (tryLockShared(arg) < 0){ //如果tryAcquireShare失败
//将当前进程放入队列
WaitNode node = new WaitNode(Thread.currentThread(), 1, arg);
waiters.offer(node); //加入队列
for (;;){
//若队列头部的元素是当前线程
WaitNode head = waiters.peek();
if (head!=null && head.thread == Thread.currentThread()){
if (tryLockShared(arg) >=0){ //尝试获取共享锁, 若成功
waiters.poll(); //将当前线程从队列中移除
WaitNode next = waiters.peek();
if (next!=null && next.type==1){ //如果下一个线程也是等待共享锁
LockSupport.unpark(next.thread); //将其唤醒
}
return; //退出方法
}else{ //若尝试失败
LockSupport.park(); //挂起线程
}
}else{ //若不是头部元素
LockSupport.park();
}
}
}
}
//解锁共享锁
public boolean unLockShared() {
int arg = 1;
if (tryUnLockShared(arg)){ //当read count变为0,才叫release share成功
WaitNode next = waiters.peek();
if (next!=null){
LockSupport.unpark(next.thread);
}
return true;
}
return false;
}
//尝试获取共享锁
public int tryLockShared(int acquires) {
for (;;){
if (writeCount.get()!=0 &&
owner.get() != Thread.currentThread())
return -1;
int rct = readCount.get();
if (readCount.compareAndSet(rct, rct + acquires)){
return 1;
}
}
}
//尝试解锁共享锁
public boolean tryUnLockShared(int releases) {
for(;;){
int rc = readCount.get();
int nextc = rc - releases;
if (readCount.compareAndSet(rc, nextc)){
return nextc==0;
}
}
}
}
- 提出公共代码后的相关代码
公共代码类:
package com.study.lock.locks5;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
public class JamesAQS {
AtomicInteger readCount = new AtomicInteger(0);
AtomicInteger writeCount = new AtomicInteger(0);
//独占锁 拥有者
AtomicReference<Thread> owner = new AtomicReference<>();
//等待队列
public volatile LinkedBlockingQueue<WaitNode> waiters = new LinkedBlockingQueue<WaitNode>();
class WaitNode{
int type = 0; //0 为想获取独占锁的线程, 1为想获取共享锁的线程
Thread thread = null;
int arg = 0;
public WaitNode(Thread thread, int type, int arg){
this.thread = thread;
this.type = type;
this.arg = arg;
}
}
//获取独占锁
public void lock() {
int arg = 1;
//尝试获取独占锁,若成功,退出方法, 若失败...
if (!tryLock(arg)){
//标记为独占锁
WaitNode waitNode = new WaitNode(Thread.currentThread(), 0, arg);
waiters.offer(waitNode); //进入等待队列
//循环尝试拿锁
for(;;){
//若队列头部是当前线程
WaitNode head = waiters.peek();
if (head!=null && head.thread == Thread.currentThread()){
if (!tryLock(arg)){ //再次尝试获取 独占锁
LockSupport.park(); //若失败,挂起线程
} else{ //若成功获取
waiters.poll(); // 将当前线程从队列头部移除
return; //并退出方法
}
}else{ //若不是队列头部元素
LockSupport.park(); //将当前线程挂起
}
}
}
}
//释放独占锁
public boolean unlock() {
int arg = 1;
//尝试释放独占锁 若失败返回true,若失败...
if(tryUnlock(arg)){
WaitNode next = waiters.peek(); //取出队列头部的元素
if (next !=null){
Thread th = next.thread;
LockSupport.unpark(th); //唤醒队列头部的线程
}
return true; //返回true
}
return false;
}
//获取共享锁
public void lockShared() {
int arg = 1;
if (tryLockShared(arg) < 0){ //如果tryAcquireShare失败
//将当前进程放入队列
WaitNode node = new WaitNode(Thread.currentThread(), 1, arg);
waiters.offer(node); //加入队列
for (;;){
//若队列头部的元素是当前线程
WaitNode head = waiters.peek();
if (head!=null && head.thread == Thread.currentThread()){
if (tryLockShared(arg) >=0){ //尝试获取共享锁, 若成功
waiters.poll(); //将当前线程从队列中移除
WaitNode next = waiters.peek();
if (next!=null && next.type==1){ //如果下一个线程也是等待共享锁
LockSupport.unpark(next.thread); //将其唤醒
}
return; //退出方法
}else{ //若尝试失败
LockSupport.park(); //挂起线程
}
}else{ //若不是头部元素
LockSupport.park();
}
}
}
}
//解锁共享锁
public boolean unLockShared() {
int arg = 1;
if (tryUnLockShared(arg)){ //当read count变为0,才叫release share成功
WaitNode next = waiters.peek();
if (next!=null){
LockSupport.unpark(next.thread);
}
return true;
}
return false;
}
//尝试获取独占锁
public boolean tryLock(int acquires) {
throw new UnsupportedOperationException();
}
//尝试释放独占锁
public boolean tryUnlock(int releases) {
throw new UnsupportedOperationException();
}
//尝试获取共享锁
public int tryLockShared(int acquires) {
throw new UnsupportedOperationException();
}
//尝试解锁共享锁
public boolean tryUnLockShared(int releases) {
throw new UnsupportedOperationException();
}
}
改写后的ReadWriteLock:
package com.study.lock.locks5;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
public class JamesReadWriteLock implements ReadWriteLock {
JamesAQS mask = new JamesAQS(){
//尝试获取独占锁
public boolean tryLock(int acquires) {
//如果read count !=0 返回false
if (readCount.get() !=0)
return false;
int wct = writeCount.get(); //拿到 独占锁 当前状态
if (wct==0){
if (writeCount.compareAndSet(wct, wct + acquires)){ //通过修改state来抢锁
owner.set(Thread.currentThread()); // 抢到锁后,直接修改owner为当前线程
return true;
}
}else if (owner.get() == Thread.currentThread()){
writeCount.set(wct + acquires); //修改count值
return true;
}
return false;
}
//尝试释放独占锁
public boolean tryUnlock(int releases) {
//若当前线程没有 持有独占锁
if(owner.get()!= Thread.currentThread()){
throw new IllegalMonitorStateException(); //抛IllegalMonitorStateException
}
int wc= writeCount.get();
int nextc = wc - releases; //计算 独占锁剩余占用
writeCount.set(nextc); //不管是否完全释放,都更新count值
if (nextc==0){ //是否完全释放
owner.compareAndSet(Thread.currentThread(), null);
return true;
}else{
return false;
}
}
//尝试获取共享锁
public int tryLockShared(int acquires) {
for (;;){
if (writeCount.get()!=0 &&
owner.get() != Thread.currentThread())
return -1;
int rct = readCount.get();
if (readCount.compareAndSet(rct, rct + acquires)){
return 1;
}
}
}
//尝试解锁共享锁
public boolean tryUnLockShared(int releases) {
for(;;){
int rc = readCount.get();
int nextc = rc - releases;
if (readCount.compareAndSet(rc, nextc)){
return nextc==0;
}
}
}
};
@Override
public Lock readLock() {
return new Lock() {
@Override
public void lock() {
mask.lockShared();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return mask.tryLockShared(1) == 1;
}
@Override
public void unlock() {
mask.unLockShared();
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
};
}
@Override
public Lock writeLock() {
return new Lock() {
@Override
public void lock() {
mask.lock();
}
@Override
public boolean tryLock() {
return mask.tryLock(1);
}
@Override
public void unlock() {
mask.unlock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
};
}
}
改写后的Reentrantlock:
package com.study.lock.locks5;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class JamesReentrantLock implements Lock {
private boolean isFair;
public JamesReentrantLock(boolean isFair){
this.isFair = isFair;
}
JamesAQS mask = new JamesAQS(){
public boolean tryLock(int acquires){
if (isFair){
return tryFairLock(acquires);
}else{
return tryNonFairLock(acquires);
}
}
//尝试获取独占锁
public boolean tryNonFairLock(int acquires) {
//如果read count !=0 返回false
if (readCount.get() !=0)
return false;
int wct = writeCount.get(); //拿到 独占锁 当前状态
if (wct==0){
if (writeCount.compareAndSet(wct, wct + acquires)){ //通过修改state来抢锁
owner.set(Thread.currentThread()); // 抢到锁后,直接修改owner为当前线程
return true;
}
}else if (owner.get() == Thread.currentThread()){
writeCount.set(wct + acquires); //修改count值
return true;
}
return false;
}
public boolean tryFairLock(int acquires){
//如果read count !=0 返回false
if (readCount.get() !=0)
return false;
int wct = writeCount.get(); //拿到 独占锁 当前状态
if (wct==0){
JamesAQS.WaitNode head = waiters.peek();
if (head!=null && head.thread == Thread.currentThread()&&
writeCount.compareAndSet(wct, wct + acquires)){ //通过修改state来抢锁
owner.set(Thread.currentThread()); // 抢到锁后,直接修改owner为当前线程
return true;
}
}else if (owner.get() == Thread.currentThread()){
writeCount.set(wct + acquires); //修改count值
return true;
}
return false;
}
//尝试释放独占锁
public boolean tryUnlock(int releases) {
//若当前线程没有 持有独占锁
if(owner.get()!= Thread.currentThread()){
throw new IllegalMonitorStateException(); //抛IllegalMonitorStateException
}
int wc= writeCount.get();
int nextc = wc - releases; //计算 独占锁剩余占用
writeCount.set(nextc); //不管是否完全释放,都更新count值
if (nextc==0){ //是否完全释放
owner.compareAndSet(Thread.currentThread(), null);
return true;
}else{
return false;
}
}
};
public void lock(){
mask.lock();
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
@Override
public boolean tryLock(){
return mask.tryLock(1);
}
@Override
public void unlock(){
mask.unlock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
}
- 原生的AQS提供的主要实现方法
- AQS源码中的主要字段
// 同步队列的head节点, 延迟初始化,除了初始化,只能通过setHead方法修改
// 如果head存在,waitStatus一定是CANCELLED
private transient volatile Node head;
// 同步队列的tail节点,延迟初始化,只能通过enq方法修改
private transient volatile Node tail;
// 同步状态
private volatile int state;
// 支持CAS
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;
6.AQS源码中的主要方法
protected final int getState() {
return state;
}
protected final void setState(int newState) {
state = newState;
}
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
// 钩子方法,独占式获取同步状态, 需要子类实现,实现此方法需要查询当前同步状态并
// 判断同步状态是否符合预期,然后再CAS设置同步状态
// 返回值true代表获取成功,false代表获取失败
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
// 钩子方法,独占式释放同步状态,需要子类实现,
// 等待获取同步状态的线程将有机会获取同步状态
// 返回值true代表获取成功,false代表获取失败
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
// 钩子方法,共享式获取同步状态,需要子类实现,
// 返回值负数代表获取失败、0代表获取成功但没有剩余资源、
// 正数代表获取成功,还有剩余资源
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
// 钩子方法,共享式释放同步状态,需要子类实现
// 返回值负数代表获取失败、0代表获取成功但没有剩余资源、
// 正数代表获取成功,还有剩余资源
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
// 模板方法,独占式获取同步状态,如果当前线程获取同步状态成功,则由该方法返回,
// 否则会进入同步队列等待,此方法会调用子类重写的tryAcquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 模板方法,独占式的释放同步状态,该方法会在释放同步状态后,
// 将同步队列中的第一个节点包含的线程唤醒
// 此方法会调用子类重写的tryRelease方法
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
// 模板方法,共享式的获取同步状态,如果当前系统未获取到同步状态,
// 将会进入同步队列等待,同一时刻可以有多个线程获取到同步状态
// 此方法会调用子类重写的tryAcquireShared方法
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
// 模板方法,共享式的释放同步状态
// 此方法会调用子类重写的tryReleaseShared方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
// 用于将当前线程加入到等待队列的队尾,并返回当前线程所在的结点
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail; // 尝试将Node放到队尾
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
//初始化或自旋CAS直到入队成功
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
2. AQS实现CountDownLatch
简述:CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。主要常用的方法countDown()方法以及await())方法。
基于AQS实现CountDownLatch
public class MyCountDownLatch {
private Sync sync;
public MyCountDownLatch(int count) {
sync = new Sync(count);
}
public void countDown() {
sync.releaseShared(1);
}
public void await() {
sync.acquireShared(1);
}
class Sync extends AbstractQueuedSynchronizer {
public Sync(int count) {
setState(count);
}
@Override
protected int tryAcquireShared(int arg) {
// 只有当state变为0时,加锁成功
return getState() == 0 ? 1 : -1;
}
@Override
protected boolean tryReleaseShared(int arg) {
for (; ; ) {
int c = getState();
if (c == 0) return false;
int nextc = c - 1;
// 用CAS操作,讲count减一
if (compareAndSetState(c, nextc)) {
// 当state=0时,释放锁成功,返回true
return nextc == 0;
}
}
}
}
}
// 测试
public class MyCountDownLatchTest {
/*
每隔1s开启一个线程,共开启6个线程
若希望6个线程 同时 执行某一操作
可以用CountDownLatch实现
*/
public static void test01() throws InterruptedException {
MyCountDownLatch ctl = new MyCountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread() {
@Override
public void run() {
ctl.countDown();
ctl.await();
System.out.println("here I am...");
}
}.start();
Thread.sleep(1000L);
}
}
/*
开启6个线程,main线程希望6个线程都执行完某个操作后,才执行某个操作
可以用CountDownLatch来实现
*/
public static void test02() throws InterruptedException {
MyCountDownLatch ctl = new MyCountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread() {
@Override
public void run() {
System.out.println("after print...");
ctl.countDown();
}
}.start();
Thread.sleep(1000L);
}
ctl.await();
System.out.println("main thread do something ...");
}
public static void main(String args[]) throws InterruptedException {
test01();
}
}