java 并发 - CyclicBarrier的用法

CyclicBarrier的用法 定义

CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

CyclicBarrier vs CountDownLatch

CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier数的是调用了CyclicBarrier.await()进入等待的线程数, 当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。 CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。 CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

package com.haleywang.demo.swing;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import javax.swing.*;

public class MyBallJDemo  {

    public static final int PLAYER_NUM = 4;

    public static void main(String[] args) {

        MyBallJPanel myBallJPanel = new MyBallJPanel();
        CyclicBarrier barrier = new CyclicBarrier(MyBallJDemo.PLAYER_NUM);
        for(int i = 0; i < PLAYER_NUM; i++) {
            MyBall myBall = new MyBall(30, 30 + 30 * i, myBallJPanel);
            myBall.setBarrier(barrier);
            myBallJPanel.getMyBalls().add(myBall);
        }

        for(MyBall b: myBallJPanel.getMyBalls()) {
            new Thread(b).start();
        }
    }

}


class MyBallJPanel extends JPanel {

    public MyBallJPanel() {
        JFrame jf = new JFrame();
        jf.setSize(new Dimension(600, 300));
        jf.setResizable(false);
        jf.setDefaultCloseOperation(3);
        jf.setLocationRelativeTo(null);
        jf.setVisible(true);

        jf.add(this, BorderLayout.CENTER);
    }

    private List<MyBall> myBalls = new ArrayList<MyBall>();

    public void paint(Graphics g) {
        super.paint(g);
        for (MyBall b : myBalls) {
            g.fillOval(b.getX(), b.getY(), 20, 20);
            g.fillRect(0, b.getY() + 10, 600, 2);
        }

        g.fillRect(200, 0, 5, 300);
        g.fillRect(400, 0, 5, 300);
    }

    public List<MyBall> getMyBalls() {
        return myBalls;
    }
}

class MyBall implements Runnable {
    private int x;
    private int y;
    private JPanel jPanel;
    private int speed = new Random().nextInt(80) + 10;
    private CyclicBarrier barrier;

    public MyBall(int x, int y, JPanel jPanel) {
        this.x = x;
        this.y = y;
        this.jPanel = jPanel;
    }

    public void setBarrier(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void run() {
        while (true) {
            updateStatus();

            jPanel.repaint();
            if (x > 400) {
                x = 0;
            }


            // game loading
            if(x == 200 && barrier != null) {
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
            // select a hero
            if(x == 400 && barrier != null) {
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    private void updateStatus() {
        x++;
        // set up speed
        try {
            Thread.sleep(speed);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}