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

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

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的加強版。dom

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()方法。尋找到裏面去。主要的邏輯就是:ide

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用法,總的來講對於一些須要作以前準備的程序來講,他們是最佳的選擇。post

相關文章
相關標籤/搜索