日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網(wǎng)站首頁 編程語言 正文

并發(fā)編程--CountdownLatch && CyclicBarrier

作者:咖啡不苦** 更新時間: 2022-06-08 編程語言

Semaphore,CountdownLatch,CyclicBarrier都是java提供的同步輔助類。
上一篇對Semaphore有了一定的了解,本篇則針對CountdownLatch以及CyclicBarrier進行一定的總結(jié)。

一、CountdownLatch

1)CountdownLatch是什么?

CyclicBarrier的字面意思是可循環(huán)使用(Cyclic)的屏障(Barrier)
能夠使一個線程等待其他線程完成各自的工作之后再執(zhí)行。例如zookeeper分布式鎖的實現(xiàn)。而Semaphore則主要強調(diào)的是資源有限。

2)CountdownLatch使用場景

比如老公陪同媳婦去醫(yī)院,媳婦等候醫(yī)生看病,老公則針對單子去拿藥,兩者都完工,則一起回家。再比如老板等10個員工開會,只有10個員工都到齊了,會議才能開始等等場景。

3)應用demo

舉例說明老板等待員工開會的場景:

public static void main(String[] args) {
		//老板需要等待15個員工會議室開會
		final CountDownLatch latch = new CountDownLatch(15);
		for (int i = 0; i < 15; i++) {
			Random random = new Random();
			final int timer = random.nextInt(1000);
			new Thread(() -> {
				try {
					System.out.println("子線程" + Thread.currentThread().getName() + "正在趕路");
					//模仿每個員工走自己線程需要的時間
					Thread.sleep(1000 + timer);
					//調(diào)用latch的countDown方法使計數(shù)器-1;一共15個
					latch.countDown();
					System.out.println("子線程" + Thread.currentThread().getName() + "到會議室了");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}).start();
		}

		try {
			System.out.println("領(lǐng)導等待員工會議室開會...");
			//主線程阻塞等待計數(shù)器歸零
			latch.await();
			System.out.println("員工都來了,會議開始");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

執(zhí)行結(jié)果:

子線程Thread-1正在趕路
子線程Thread-3正在趕路
子線程Thread-0正在趕路
子線程Thread-2正在趕路
子線程Thread-4正在趕路
子線程Thread-5正在趕路
子線程Thread-6正在趕路
子線程Thread-7正在趕路
子線程Thread-8正在趕路
子線程Thread-9正在趕路
子線程Thread-10正在趕路
子線程Thread-11正在趕路
子線程Thread-12正在趕路
子線程Thread-13正在趕路
領(lǐng)導等待員工會議室開會…
子線程Thread-14正在趕路
子線程Thread-5到會議室了
子線程Thread-1到會議室了
子線程Thread-12到會議室了
子線程Thread-13到會議室了
子線程Thread-4到會議室了
子線程Thread-6到會議室了
子線程Thread-2到會議室了
子線程Thread-0到會議室了
子線程Thread-3到會議室了
子線程Thread-10到會議室了
子線程Thread-14到會議室了
子線程Thread-8到會議室了
子線程Thread-9到會議室了
子線程Thread-7到會議室了
子線程Thread-11到會議室了
員工都來了,會議開始

4)源碼分析

核心關(guān)注方法只有兩個,latch.countDown();和latch.await();
countDown() 方法每次調(diào)用都會將 state 減 1,直到state 的值為 0;而 await 是一個阻塞方法,當 state 減 為 0 的時候,await 方法才會返回。await 可以被多個線程調(diào)用,大家在這個時候腦子里要有個圖:所有調(diào)用了await 方法的線程阻塞在 AQS 的阻塞隊列中,等待條件滿(state == 0),將線程從隊列中一個個喚醒過來。

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

在 CountDownLatch 內(nèi)部寫了一個 Sync 并且繼承了 AQS 這個抽象類重寫了 AQS中的共享鎖方法。這段代碼主要是判定當前線程是否獲取到了共享鎖
在這里插入圖片描述

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        //state 如果不等于 0,說明當前線程需要加入到共享鎖隊列中
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
//在共享可中斷模式下獲取。
private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        //創(chuàng)建一個共享模式的節(jié)點添加到隊列中
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    //嘗試獲取鎖
                    int r = tryAcquireShared(arg);
                    //r>=0 表示獲取到了執(zhí)行權(quán)限,這個時候因為 state!=0,所以不會執(zhí)行這段代碼
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                //阻塞線程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

二、CyclicBarrier

1)CyclicBarrier是什么?

柵欄屏障,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續(xù)運行。
簡單理解就是:多個線程之間互相等待,滿足條件在同一時間進行。

2)CyclicBarrier使用場景

可以用于多線程計算數(shù)據(jù),最后合并計算結(jié)果的場景。
又比如旅行團旅行,需要大家都到齊,證件都辦理好,才能出發(fā)。

3)應用demo

旅行團旅行,需要大家都到齊,證件都辦理好,上旅行車才能出發(fā)。

public class CyclicBarrierTest1 extends Thread{
	private final CyclicBarrier barrier;
	//隨機值處理
	private final Random random = new Random();
	public CyclicBarrierTest1(String name,CyclicBarrier barrier) {
		super(name);
		this.barrier = barrier;
	}

	/**
	 * 重寫run方法
	 */
	@Override
	public void run() {
		try {
			Thread.sleep(random.nextInt(2000));
			System.out.println(Thread.currentThread().getName() + " - 已經(jīng)到達旅行團");
			barrier.await();
			Thread.sleep(random.nextInt(2000));
			System.out.println(Thread.currentThread().getName() + " - 證件已經(jīng)辦理好");
			barrier.await();
			Thread.sleep(random.nextInt(2000));
			System.out.println(Thread.currentThread().getName() + " - 已經(jīng)上旅行車");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
		super.run();
	}

	public static void main(String[] args) {
		//旅行團5個游客
		CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
		for (int i=0;i<5;i++){
			new CyclicBarrierTest1("游客-" + (i + 1), cyclicBarrier).start();
		}
	}
}

游客-5 - 已經(jīng)到達旅行團
游客-3 - 已經(jīng)到達旅行團
游客-2 - 已經(jīng)到達旅行團
游客-1 - 已經(jīng)到達旅行團
游客-4 - 已經(jīng)到達旅行團
游客-2 - 證件已經(jīng)辦理好
游客-4 - 證件已經(jīng)辦理好
游客-1 - 證件已經(jīng)辦理好
游客-3 - 證件已經(jīng)辦理好
游客-5 - 證件已經(jīng)辦理好
游客-1 - 已經(jīng)上旅行車
游客-2 - 已經(jīng)上旅行車
游客-3 - 已經(jīng)上旅行車
游客-5 - 已經(jīng)上旅行車
游客-4 - 已經(jīng)上旅行車

原文鏈接:https://blog.csdn.net/huo065000/article/details/120649318

欄目分類
最近更新