Java 并發專題 : CyclicBarrier 打造一個安全的門禁系統

jopen 8年前發布 | 6K 次閱讀 Java開發

繼續并發專題~

這次介紹CyclicBarrier:看一眼API的注釋:

/**
 * A synchronization aid that allows a set of threads to all wait for
 * each other to reach a common barrier point.  CyclicBarriers are
 * useful in programs involving a fixed sized party of threads that
 * must occasionally wait for each other. The barrier is called
 * <em>cyclic</em> because it can be re-used after the waiting threads
 * are released.

大概意思:一個讓一組線程同時阻塞到一個位置的同步輔助類。在包含固定線程且線程間必須相互等待的場景中非常有用。cyclic的意思是CyclicBarrier當等待的線程全部釋放之后,可以重復使用。(英語水平就這樣了。。。。)

CyclicBarrier 類似一個閘門,指定數目的線程都必須到達這個閘門,閘門才會打開。

下面使用CyclicBarrier模擬一個門禁系統:

需求是這樣的:到放學時間,所有的學生必須刷卡,然后人數齊了自動開門,統一回家。這個需求剛剛的,避免了把部分孩子丟在學校發生危險,特別是幼兒園或者小學生~~

package com.zhy.concurrency.cyclic;

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

/**
 * 安全的門禁系統
 * 
 * @author zhy
 * 
 */
public class CyclicBarrierTest
{

    /**
     * 學生總數
     */
    private final int STUDENT_COUNT = 10;

    /**
     * 當人到齊,自動開門程序
     */
    final CyclicBarrier barrier = new CyclicBarrier(STUDENT_COUNT,
            new Runnable()
            {
                @Override
                public void run()
                {
                    System.out.println("人到齊了,開門....");
                }
            });

    public void goHome() throws InterruptedException, BrokenBarrierException
    {
        System.out.println(Thread.currentThread().getName() + "已刷卡,等待開門回家~");
        barrier.await();
        System.out.println(Thread.currentThread().getName() + "放學回家~");
    }

    public static void main(String[] args) throws InterruptedException,
            BrokenBarrierException
    {

        final CyclicBarrierTest instance = new CyclicBarrierTest();

        /**
         * 每個線程代表一個學生
         */
        for (int i = 0; i < instance.STUDENT_COUNT; i++)
        {
            new Thread("學生" + i +"  " )
            {
                public void run()
                {

                    try
                    {
                        instance.goHome();
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e)
                    {
                        e.printStackTrace();
                    }

                };

            }.start();
        }

    }
}

輸出結果:

學生1  已刷卡,等待開門回家~
學生3  已刷卡,等待開門回家~
學生5  已刷卡,等待開門回家~
學生9  已刷卡,等待開門回家~
學生7  已刷卡,等待開門回家~
學生0  已刷卡,等待開門回家~
學生2  已刷卡,等待開門回家~
學生6  已刷卡,等待開門回家~
學生8  已刷卡,等待開門回家~
學生4  已刷卡,等待開門回家~
人到齊了,開門....
學生4  放學回家~
學生1  放學回家~
學生3  放學回家~
學生5  放學回家~
學生9  放學回家~
學生2  放學回家~
學生6  放學回家~
學生0  放學回家~
學生7  放學回家~
學生8  放學回家~

哈哈,如果哪個幼兒園用了這么一套系統,孩子應該不會丟學校了吧,,,,開玩笑了;;

CyclicBarrier把所有的線程都阻塞在一個閥門位置,然后等到等待的線程數到達預設的值,就打開這個閥門。記得是阻塞線程,不是阻塞操作,在同一個線程使勁掉await是沒什么效果的。


上面的例子顯示了CyclicBarrier的基本用法,但是cyclic的功能并沒有顯示出來,既然注釋中講了,我們有必要來個例子看看:

我們改造下我們的門禁,畢竟刷卡好不現實,現在需求是這樣的:學生一個人走太危險,現在門衛放學在門口守著,讓學生3個一組的走。

package com.zhy.concurrency.cyclic;

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

/**
 * 改造后的門禁系統
 * 
 * @author zhy
 * 
 */
public class CyclicBarrierTest2
{

    /**
     * 學生總數
     */
    private final int STUDENT_COUNT = 12;

    /**
     * 每3個人一組出門
     */
    final CyclicBarrier barrier = new CyclicBarrier(3,
            new Runnable()
            {
                @Override
                public void run()
                {
                    System.out.println("有3個學生到齊了,放行....");
                }
            });

    public void goHome() throws InterruptedException, BrokenBarrierException
    {
        System.out.println(Thread.currentThread().getName() + "已刷卡,等待開門回家~");
        barrier.await();
    }

    public static void main(String[] args) throws InterruptedException,
            BrokenBarrierException
    {

        final CyclicBarrierTest2 instance = new CyclicBarrierTest2();

        /**
         * 每個線程代表一個學生
         */
        for (int i = 0; i < instance.STUDENT_COUNT; i++)
        {
            new Thread("學生" + i +"  " )
            {
                public void run()
                {

                    try
                    {
                        instance.goHome();
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e)
                    {
                        e.printStackTrace();
                    }

                };

            }.start();
        }

    }
}
輸出結果:

學生0  已刷卡,等待開門回家~
學生1  已刷卡,等待開門回家~
學生2  已刷卡,等待開門回家~
有3個學生到齊了,放行....
學生3  已刷卡,等待開門回家~
學生5  已刷卡,等待開門回家~
學生7  已刷卡,等待開門回家~
有3個學生到齊了,放行....
學生4  已刷卡,等待開門回家~
學生9  已刷卡,等待開門回家~
學生6  已刷卡,等待開門回家~
有3個學生到齊了,放行....
學生11  已刷卡,等待開門回家~
學生10  已刷卡,等待開門回家~
學生8  已刷卡,等待開門回家~
有3個學生到齊了,放行....

這個例子充分的體現了CyclicBarrier的復用性,是吧,這樣的系統或許更實在些,0成本~哈哈~。


好了,有興趣的歡迎留言、

來自: http://blog.csdn.net//lmj623565791/article/details/26829117

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!