[置顶] java并发编程——八 CountDownLatch CyclicBarrier Exchanger

从这章开始介绍 java.concurrent.*中的常用并发工具类,并附带有趣的示例

CountDownLatch

  • 概要

    比如5个任务同时运行,Task F 要求在 Task A 、Task B 、Task C、Task D、Task E  都完成后执行.那么使用CountDownLatch对象,并设置一个初始值,如 CountDownLatch countDownLatch  = new CountDownLatch(5).
    
    在Task F中调用countDownLatch.await()阻塞该任务,直到count值为0时,自动运行。
    
    Task A....Task E ,这5个任务中,调用countDownLatch.countDown(),表示每完成一个任务就将count值减一.
    
    Task A...E运行完之后,Task F将不再阻塞,立刻运行
    

以上描述对应代码实现:

class PortionTask implements Runnable {

    private static int counter = 0;
    private int id = counter++;
    private CountDownLatch countDownLatch;

    public PortionTask(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println("portion task complete " + this + " Thread[" + Thread.currentThread().getName() + "]");
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        countDownLatch.countDown();
    }

    @Override
    public String toString() {
        return "PortionTask [id=" + id + "]";
    }

}

class TaskWaiting implements Runnable {

    private CountDownLatch countDownLatch;

    public TaskWaiting(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("it's my turn " + this);
    }

}

public class CountDownLatchDemoMine {
    public static void main(String[] args) {
        int SIZE = 5;

        CountDownLatch c = new CountDownLatch(SIZE);

        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new PortionTask(c));// A Task
        exec.execute(new PortionTask(c));// B Task
        exec.execute(new PortionTask(c));// C Task
        exec.execute(new PortionTask(c));// D Task
        exec.execute(new PortionTask(c));// E Task
        exec.execute(new TaskWaiting(c));// Final Task F
        exec.shutdown();
    }
}

CyclicBarrier

直接上代码,一个很多有趣的短跑比赛模拟程序,详见注释,看完你就理解了CyclicBarrier:

class Player implements Runnable {

    private static int counter = 0;
    private int id = counter++;
    private int moveDistance;
    private static CyclicBarrier barrier;
    private static Random random = new Random(47);

    public Player(CyclicBarrier b) {
        barrier = b;
    }

    public int getMoveDistance() {
        return moveDistance;
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            moveDistance += random.nextInt(3);
            try {
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public String toString() {
        return "" + id;
    }

}

public class Race {
    private int playerNum = 5;
    private int finalLine = 20;
    private CyclicBarrier barrier;// 唯一的CyclicBarrier对象

    private List<Player> players = new ArrayList<Player>();
    private ExecutorService es = Executors.newCachedThreadPool();

    public Race() {

        // 1 构建CyclicBarrier(int parties, Runnable barrierAction)
        // 当n个player都在这个barrier上调用了barrier.await(),这个barrier
        // 对象将重置,并使用最后一个调用await的线程去运行barrierAction,
        // 唤醒所有wait的线程,
        // 然后再一次等待nHourse全部执行await....周而复始;直到shutdownNow
        // 查看CyclicBarrier构造器的JDoc,有详细描述
        barrier = new CyclicBarrier(playerNum, new Runnable() {
            @Override
            public void run() {
                // 1.打印赛道
                StringBuffer raceLine = new StringBuffer();
                raceLine.append(" ");
                for (int i = 0; i < finalLine; i++) {
                    raceLine.append("=");
                }
                System.out.println(" 100米男子赛道");
                System.out.println(raceLine);

                // 2.打印当前参赛者行进位置
                for (Player player : players) {
                    StringBuffer playerLocation = new StringBuffer();
                    playerLocation.append(player);
                    for (int i = 0; i < player.getMoveDistance(); i++) {
                        playerLocation.append("*");
                    }
                    System.out.println(playerLocation);

                }
                // 3.检查是否有参赛者完成比赛,如果是,结束比赛;
                // (会存在多个player同时越过终点)
                for (Player player : players) {
                    if (player.getMoveDistance() >= finalLine) {
                        System.out.println("bravo: player" + player + " won!!! ");
                        es.shutdownNow();// 该方法并不保证池中所有线程退出
                        return;
                    }

                }
                try {
                    TimeUnit.MILLISECONDS.sleep(80);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        // 2.任务执行:所有player开始跑
        for (int i = 0; i < playerNum; i++) {
            // 每个Player中传入同一个CyclicBarrier对象
            Player p = new Player(barrier);
            players.add(p);
            es.execute(p);
        }
    }

    public static void main(String[] args) {
        new Race();

    }

}

output:

 100米男子赛道
 ==========
0**
1**
2*
3**
4*

..............................


 100米男子赛道
 ==========
0*******
1*********
2*****
3******
4******
 100米男子赛道
 ==========
0********
1**********
2*****
3*******
4******
bravo: player1 won!!! 

Exchanger

示例描述:
一个生产者线程生产消息 msgX,然后调用exchanger.exchang(msgX),此时该线程Blocked,等待另一个线程(消费者)去消费:消费者调用 exchanger.exchange(“此参数会传递给生产者线程,并不需要”),获得生成者刚才生成的消息,并唤醒阻塞的生产者.

public class ExchangerTest {

    private static final Exchanger<List<String>> exgr = new Exchanger<List<String>>();

    private static ExecutorService threadPool = Executors.newFixedThreadPool(10);

    private static Random rand = new Random(47);

    private static Runnable producerProductMsg() {
        return new Runnable() {

            @Override
            public void run() {
                List<String> producerMsgX = new ArrayList<String>();
                for (int i = 0; i < 10; i++) {
                    producerMsgX.add(i + rand.nextInt(100) + "");
                }
                try {
                    // 生产,阻塞
                    // Waits for another thread to arrive at this exchange
                    // point
                    exgr.exchange(producerMsgX);
                    System.out.println(" ThreadName:" + Thread.currentThread().getName() + " producerProductMsg:"
                            + producerMsgX);

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

        };
    }

    private static Runnable consumerConsumeMsg() {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    List<String> getMsgFromProducer = exgr.exchange(new ArrayList<String>());
                    System.out.println(" ThreadName:" + Thread.currentThread().getName() + " consumerConsumeMsg:"
                            + getMsgFromProducer);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

        };
    }

    public static void main(String[] args) {

        // 消息生成者
        threadPool.execute(producerProductMsg());
        // 消费者 消费
        threadPool.execute(consumerConsumeMsg());
        threadPool.shutdown();
    }
}

你可能感兴趣的:(并发,Exchanger,await,countDown,barrier)