java并发之同步工具类三之栅栏Barrier

栅栏和闭锁在Java并发中都能使线程同步,但有所不同。闭锁等待特定事件,而栅栏则等待所有线程准备就绪后再一起执行。以赛跑为例,闭锁如同裁判发令,而栅栏则是所有运动员相互等待。当使用栅栏时,若某线程超时或中止,所有线程将终止并抛出异常,确保所有操作一致性。本文通过修改之前的赛跑案例,展示了如何使用栅栏实现线程同步。

栅栏闭锁是有同样的功能的,都可以让所有线程都阻塞在同一个位置。唯一不同的是,闭锁等待的是事件,而栅栏等待的是一起执行的其他线程。
在之前的博客中 java并发之同步工具类一之闭锁Latch引用了一个赛跑案例,运动员相当于多个并发的子线程,而裁判就是主线程。运动员的就绪等待的是裁判起跑枪指令(即一个事件),当起跑枪发射所有运动员就同时开始跑。这是闭锁的实现方式,而栅栏不同,它没有裁判这个角色,它是观察并等待所有一起跑的运动员都准备就绪后开始跑。这种场景显示中可能会更常见,如几个好朋友约定3点半在广州图书馆门口相见,到了3点半如果有一人没到,其他人就一起等待。这种场景,就是没有裁判这个角色的,等待不是一个事件,而是所有朋友。
栅栏还有个不同,如果其中有一个线程超时或者中止,所有线程都将会终止并抛出BrokenBarrierException,因为没有事件指令,只能通过其他线程共同来维护,一个线程不能就绪其他也就都失败。而这个,就能确保了其他线程也都全部完成了上面的步骤。
我们依旧使用原来的跑步案例,更改起跑限制为栅栏,实现如下


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

/**
 *
 * @author Jerry 自由比赛与CycleBarrier
 * @date 2017/12/24 0024
 */
public class SelfMatch {
    public static void main(String[] args) {
        int joinMatchCnt = 5;//参加比赛的人数
        CyclicBarrier beginMatchFlag = new CyclicBarrier(joinMatchCnt);
        CountDownLatch finishFlag = new CountDownLatch(joinMatchCnt);
        System.out.println("比赛准备开始.....");
        for (int i = 1; i <= joinMatchCnt; i++) {
            Thread t = new Thread(new Sportsman(beginMatchFlag, finishFlag, i + "号"));
            System.out.println(i + "号已就位");
            t.start();//所有运动员都到指定位置就绪
        }
        try {
            finishFlag.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("比赛结束.....");
    }

    static class Sportsman implements Runnable {
        private CyclicBarrier beginMatchFlag;
        private CountDownLatch finishFlag;
        private String name;

        public Sportsman(CyclicBarrier beginMatchFlag, CountDownLatch finishFlag, String name) {
            this.beginMatchFlag = beginMatchFlag;
            this.finishFlag = finishFlag;
            this.name = name;
        }

        @Override
        public void run() {

                try {
                    beginMatchFlag.await();//等待所有队员就绪完毕
                    try {
                        running();
                    } finally {
                        System.out.println("运动员" + name + "跑到终点线");
                        finishFlag.countDown();//运动员跑到终点,这里要放在finally中,如运动员跑步受伤,立即终止个人成绩
                    }

                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


        }

        private void running() {
            try {
                System.out.println("运动员" + name + "开始比赛");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

同样的,执行结果与闭锁一样。

比赛准备开始.....
1号已就位
2号已就位
3号已就位
4号已就位
5号已就位
运动员5号开始比赛
运动员4号开始比赛
运动员3号开始比赛
运动员2号开始比赛
运动员1号开始比赛
运动员4号跑到终点线
运动员5号跑到终点线
运动员2号跑到终点线
运动员1号跑到终点线
运动员3号跑到终点线
比赛结束.....
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值