JAVA併發之多線程基礎(4)

NO IMAGE

JAVA併發之多線程基礎(4)

繼上篇文章JAVA併發之多線程基礎(3)談到的信號量以及讀寫鎖之外,接下來就繼續談及JDK中併發類的操作。

CountDownLatch

倒計時器是在某一些程序需要前置處理的時候完美搭檔。例如我們經常玩的手遊端,在遊戲開始之前,它會去調用其他的組件,例如畫面環境、人物圖像、武器裝備等,等加載完成之後再進入到主界面中進行遊戲。

  1. countDown()方法是每個線程完成之後減1,代表一個線程已經到達了終點線。我們可以點擊進去看到裡面調用的方法:
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {//試圖將一個線程設置共享模式
doReleaseShared();//共享模式下的釋放操作
return true;
}
return false;
}
  1. await()是每個線程要到達的終點線,先執行完成的線程需在此等待未完成任務的線程。直至當前的countDown數量到0。
 public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())//判斷線程是否是中斷
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)//嘗試在共享模式下獲取
doAcquireSharedInterruptibly(arg);//在共享可中斷模式下獲取。
}

demo:

package com.montos.lock;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo implements Runnable {
static final CountDownLatchDemo demo = new CountDownLatchDemo();
static final CountDownLatch latch = new CountDownLatch(10);
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println("checking....");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
exec.submit(demo);
}
latch.await();
System.out.println("prepare is end");
exec.shutdown();
}
}

CyclicBarrier

柵欄是指每一個線程在某一處等待集合,然後接下來繼續執行又到了某一處進行集合等待。可以說是上面CountDownLatch的增強版。

package com.montos.lock;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static class Soldier implements Runnable {
private String name;
private final CyclicBarrier cycli;
public Soldier(String name, CyclicBarrier cycli) {
super();
this.name = name;
this.cycli = cycli;
}
@Override
public void run() {
try {
cycli.await();//十個線程一起等待集合
doSometing();
cycli.await();//十個線程一起等待事情處理完畢
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
private void doSometing() {
try {
Thread.sleep(new Random().nextInt(5) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "任務完成");
}
}
public static class BarrierRun implements Runnable {
boolean flag;
int N;
public BarrierRun(boolean flag, int n) {
super();
this.flag = flag;
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[10];
boolean flag = false;
//N個線程到達之後,需要處理什麼事情(這裡是一起到達之後,處理BarrierRun事件)
CyclicBarrier cycli = new CyclicBarrier(N, new BarrierRun(flag, N));
System.out.println("集合隊伍");
for (int i = 0; i < 10; i++) {
System.out.println("士兵" + i + "報道!");
allSoldier[i] = new Thread(new Soldier("士" + i, cycli));
allSoldier[i].start();
}
}
}
}

通過上面一個小的demo,可以看到CyclicBarrier的用法。其中主要的就是await()方法。尋找到裡面去。主要的邏輯就是:

for (;;) {
try {
if (!timed)
trip.await();//調用重入鎖中的condition進行當前線程等待
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);//時間限制等待
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();//將當前的屏障一代設置為斷開並喚醒所有人
throw ie;
} else {
Thread.currentThread().interrupt();//當前線程中斷
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}

這上面就是對對應方法中的一個講解。裡面也用到了重入鎖。通過上面的demo也知道CyclicBarrierCountDownLatch用法,總的來說對於一些需要做之前準備的程序來說,他們是最佳的選擇。

相關文章

JAVA鎖介紹

JAVA操作碼相關指令介紹

JAVA併發之多線程基礎(6)

JAVA併發之多線程基礎(5)