天天看點

《java并發程式設計實戰》第五章閉鎖和栅欄

先說兩點都知道的: 

1.CountDownLatch減計數,CyclicBarrier加計數。 

2.CountDownLatch是一次性的,CyclicBarrier可以重用。 

      閉鎖是一種同步工具類,可以延遲線程的進度直到其到達終止狀态,當閉鎖到達結束狀态後,将不會再改變狀态。閉鎖可以用來確定某些活動直到其他活動都完成後才繼續執行。

     countDown方法遞減計數器,表示有一個時間發生了,而await方法等待計數器到達為零,這表示所有需要等待的時間都已經發生。如果計數器為非零,那麼await會一直阻塞直到計數器為零,或者等到中的線程中斷,或者等待逾時。

import java.util.concurrent.CountDownLatch;

public class Race {
public static void main(String[] args) {
final int num = 5;
final CountDownLatch begin = new CountDownLatch(1);
final CountDownLatch end = new CountDownLatch(num);

for (int i = 0; i < num; i++) {
new Thread(new AWorker(i, begin, end)).start();
}

// judge prepare...
try {
Thread.sleep((long) (Math.random() * 5000));
} catch (InterruptedException e1) {
e1.printStackTrace();
}


System.out.println("judge say : run !");
begin.countDown();
long startTime = System.currentTimeMillis();


try {
end.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
long endTime = System.currentTimeMillis();
System.out.println("judge say : all arrived !");
System.out.println("spend time: " + (endTime - startTime));
}


}

}

class AWorker implements Runnable {
final CountDownLatch begin;
final CountDownLatch end;
final int id;


public AWorker(final int id, final CountDownLatch begin,
final CountDownLatch end) {
this.id = id;
this.begin = begin;
this.end = end;
}


@Override
public void run() {
try {
System.out.println(this.id + " ready !");
begin.await();
// run...
Thread.sleep((long) (Math.random() * 10000));
} catch (Throwable e) {
e.printStackTrace();
} finally {
System.out.println(this.id + " arrived !");
end.countDown();
}
}


}
           

CountDownLatch強調的是一個線程(或多個)需要等待另外的n個線程幹完某件事情之後才能繼續執行。 上述例子,main線程是裁判,5個AWorker是跑步的。運動員先準備,裁判喊跑,運動員才開始跑(這是第一次同步,對應begin)。5個人誰跑到終點了,countdown一下,直到5個人全部到達,裁判喊停(這是第二次同步,對應end),然後算時間。

2. 繼續,還是這五個人(這五個人真無聊..),這次沒裁判。規定五個人隻要都跑到終點了,大家可以喝啤酒。但是,隻要有一個人沒到終點,就不能喝。 這裡也沒有要求大家要同時起跑(當然也可以,加latch)。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Beer {

public static void main(String[] args) {
final int count = 5;
final CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() {
@Override
public void run() {
System.out.println("drink beer!");
}
});

// they do not have to start at the same time...
for (int i = 0; i < count; i++) {
new Thread(new Worker(i, barrier)).start();
}
}


}

class Worker implements Runnable {
final int id;
final CyclicBarrier barrier;

public Worker(final int id, final CyclicBarrier barrier) {
this.id = id;
this.barrier = barrier;
}

@Override
public void run() {
try {
System.out.println(this.id + "starts to run !");
Thread.sleep((long) (Math.random() * 10000));
System.out.println(this.id + "arrived !");
this.barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}