Zookeeper应用之——栅栏(barrier)

栅栏(barrier)简介

barrier的作用是所有的线程等待,知道某一时刻,锁释放,所有的线程同时执行。举一个生动的例子,比如跑步比赛,所有 运动员都要在起跑线上等待,直到枪声响后,所有运动员同时起跑,冲向终点。在这个例子中,所有的运动员就是所有的线程, 枪声是所有线程的共享锁,枪声一响,锁释放,所有线程同时执行。

java的concurrent包中已经为我们提供了barrier的实现,它叫做CyclicBarrier。但是它只能在一个java进程中提供barrier, 在分布式、集群的情况下,java是不能提供barrier的。在分布式、集群的环境下,我们需要借助外部工具实现barrier,今天我们 介绍使用zookeeper实现barrier。

Zookeeper实现Barrier的方式

Zookeeper的安装,无论是集群还是单点,请参阅其他文档,这里不再赘述了。Zookeeper的基本概念,如:节点、临时节点、 树结构、观察器(watcher)等请参阅上一篇文章,这里也不细讲。

我们通过在Zookeeper设置栅栏节点实现Barrier,节点的名字我们叫做/zookeeper/barrier,具体的逻辑如下:

  1. 客户端在Barrier节点上调用exists()方法,并设置观察器
  2. 如果Barrier节点不存在,则线程继续执行
  3. 如果Barrier节点存在,则线程等待,直到触发观察器事件,并且事件是Barrier节点消失的事件,唤起线程

具体程序实现

首先连接Zookeeper,创建Barrier节点,如下:

[root@vultr ~]# /opt/zookeeper-3.5.4-beta/bin/zkCli.sh -server localhost:2181

[zk: localhost:2181(CONNECTED) 1] create /zookeeper/barrier
Created /zookeeper/barrier

然后我们创建类BarrierExample,如下:

public class BarrierExample implements Runnable,Watcher {

    private ZooKeeper zk;

    /**
* 构造函数
* @param address zookeeper地址
*/
public BarrierExample(String address){
try {
this.zk = new ZooKeeper(address,3000,this);
} catch (IOException e) {
e.printStackTrace();
this.zk = null;
}
} @Override
public void run() {
try {
//监听Barrier节点,并设置观察器
Stat stat = zk.exists("/zookeeper/barrier", true);
//Barrier节点存在,线程等待
if (stat!=null){
System.out.println(Thread.currentThread().getName()+"——barrier节点存在,线程等待");
synchronized (this){
this.wait();
}
}
//模拟业务代码
businessCode();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} /**
* 模拟业务代码
*/
private void businessCode() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"——执行业务逻辑耗时:2s");
} catch (InterruptedException e) {
e.printStackTrace();
} } /**
* 观察器
* @param event
*/
@Override
public void process(WatchedEvent event) {
//不是节点删除事件,返回
if (event.getType() != Event.EventType.NodeDeleted) return;
try {
//查看Barrier节点是否存在
Stat stat = zk.exists("/zookeeper/barrier", true);
//Barrier节点消失,唤起所有等待线程
if (stat==null){
System.out.println(Thread.currentThread().getName()+"——barrier节点消失,唤起所有线程");
synchronized (this) {
this.notify();
}
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

BarrierExample实现了Runnable和Watcher接口,线程开始时,会调用run()方法,发现Barrier节点存在,线程等待。 然后我们将Barrier节点删除,触发Watch事件,发现Barrier节点已消失,唤起等待的线程。接下来,创建主函数类:

public class Application {
public static void main(String[] args) {
//设置log级别为Error
setLog(); //创建5个线程
ExecutorService es = Executors.newFixedThreadPool(5); for (int i=0;i<5;i++){
//执行BarrierExample
es.execute(new BarrierExample("149.28.37.147:2181"));
}
es.shutdown(); System.out.println("主线程完成!");
} /**
* 设置log级别为Error
*/
public static void setLog(){
//1.logback
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
//获取应用中的所有logger实例
List<Logger> loggerList = loggerContext.getLoggerList(); //遍历更改每个logger实例的级别,可以通过http请求传递参数进行动态配置
for (ch.qos.logback.classic.Logger logger:loggerList){
logger.setLevel(Level.toLevel("ERROR"));
}
}
}

我们创建了5个线程,发现Barrier节点,等待,具体执行如下:

运行main()函数,后台打印结果如下:

主线程完成!
pool-1-thread-1——barrier节点存在,线程等待
pool-1-thread-5——barrier节点存在,线程等待
pool-1-thread-2——barrier节点存在,线程等待
pool-1-thread-4——barrier节点存在,线程等待
pool-1-thread-3——barrier节点存在,线程等待

然后我们将Barrier节点删除:

[zk: localhost:2181(CONNECTED) 0] delete /zookeeper/barrier

Barrier节点消失,唤起所有等待线程,后台打印结果如下:

main-EventThread——barrier节点消失,唤起所有线程
main-EventThread——barrier节点消失,唤起所有线程
main-EventThread——barrier节点消失,唤起所有线程
main-EventThread——barrier节点消失,唤起所有线程
main-EventThread——barrier节点消失,唤起所有线程
pool-1-thread-2——执行业务逻辑耗时:2s
pool-1-thread-1——执行业务逻辑耗时:2s
pool-1-thread-5——执行业务逻辑耗时:2s
pool-1-thread-3——执行业务逻辑耗时:2s
pool-1-thread-4——执行业务逻辑耗时:2s

Zookeeper的Barrier实现就介绍完了,以后我们还会介绍Zookeeper的其他应用。

Zookeeper应用之——栅栏(barrier)的更多相关文章

  1. ZooKeeper实现同步屏障(Barrier)

    按照维基百科的解释:同步屏障(Barrier)是并行计算中的一种同步方法.对于一群进程或线程,程序中的一个同步屏障意味着任何线程/进程执行到此后必须等待,直到所有线程/进程都到达此点才可继续执行下文. ...

  2. CountDownLatch 闭锁、FutureTask、Semaphore信号量、Barrier栅栏

    同步工具类可以是任何一个对象.阻塞队列可以作为同步工具类,其他类型的同步工具类还包括信号量(Semaphore).栅栏(Barrier).以及闭锁(Latch). 所有的同步工具类都包含一些特定的结构 ...

  3. 06.Curator Barrier

        分布式Barrier是这样一个类: 它会阻塞所有节点上的等待进程,知道某一个被满足, 然后所有的节点继续进行.     比如赛马比赛中, 等赛马陆续来到起跑线前. 一声令下,所有的赛马都飞奔而 ...

  4. ZooKeeper Recipes and Solutions 翻译

    ZooKeeper 秘诀 与解决方案 A Guide to Creating Higher-level Constructs with ZooKeeper Out of the Box Applica ...

  5. [转载] 跟着实例学习zookeeper 的用法

    原文: http://ifeve.com/zookeeper-curato-framework/ zookeeper 的原生客户端库过于底层, 用户为了使用 zookeeper需要编写大量的代码, 为 ...

  6. 17. ZooKeeper常见的分布式系统任务——屏障

    以后几节中主要介绍以下内容: 如何执行领导者选举,组员管理和两阶段提交协议等常见的分布式系统任务 如何实现一些分布式数据结构,如屏障(barrier),锁(lock)和队列(queue) 这一章中概述 ...

  7. ZooKeeper 学习资料积累

    跟着实例学习ZooKeeper的用法: 临时节点 跟着实例学习ZooKeeper的用法: 缓存 跟着实例学习ZooKeeper的用法: 队列 跟着实例学习ZooKeeper的用法: Barrier 跟 ...

  8. ZooKeeper Recipes and Solutions

    原文地址:http://zookeeper.apache.org/doc/current/recipes.html 参考:https://zookeeper.apache.org/doc/trunk/ ...

  9. 【JAVA并发编程实战】10、并发程序的测试

    1.产生随机数 package cn.study.concurrency.ch12; public class Util { public static int xorShift(int y) { / ...

随机推荐

  1. python 读取mysql数据至csv文件中,并发送邮件

    test 代码: #coding:utf-8 ''' Created on 2019年2月18日 @author: Administrator ''' import ConfigParser impo ...

  2. 删除SQL架构的用户

    ALTER AUTHORIZATION ON SCHEMA::db_owner TO db_owner

  3. Groovy和Java互调

    Scala和Java为静态语言,Groovy为动态语言 Scala: 函数式编程,同时支持面向对象 Groovy: jvm上的脚本,较好兼容java语法,Groovy加强了Java集成. 可配置化的优 ...

  4. 并发编程基础之volatile关键字的用法

    一:概念 volatile关键字是一个轻量级的线程同步,它可以保证线程之间对于共享变量的同步,假设有两个线程a和b, 它们都可以访问一个成员变量,当a修改成员变量的值的时候,要保证b也能够取得成员变量 ...

  5. SQLSERVER查询那个表里有数据

    declare @table table (rows int,tablename nvarchar(100));declare @sql NVARCHAR(MAX)declare @rows int; ...

  6. docker必须要sudo,但是sudo的话,又获得不了环境变量怎么办?

    方法1 sudo usermod -a -G docker $USER 方法2 sudo -E docker-compose ... 在sudo后面加上-E

  7. 一、K3 WISE 实施顾问教程《进度1-谈谈实施顾问》

    1.为什么要开这门课? 从自身的原因说起,在我从开发顾问转岗做实施顾问.售后服务顾问时,我就定下了我做顾问的目标. 第一个核心目标,帮助成千上万的企业客户促进他们商业的成功!第二个目标,成为最顶级的顾 ...

  8. 算法提高 金属采集_树形dp

    算法提高 金属采集   时间限制:1.0s   内存限制:256.0MB        问题描述 人类在火星上发现了一种新的金属!这些金属分布在一些奇怪的地方,不妨叫它节点好了.一些节点之间有道路相连 ...

  9. cmder 常用配置(包括默认管理员运行和解决中文乱码)

    简介 cmder是一个增强型命令行工具,不仅可以使用windows下的所有命令,更爽的是可以使用linux的命令,shell命令. 下载 官网地址:http://cmder.net/ 下载的时候,会有 ...

  10. PTA地下迷宫探索

    地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式.地道网是房连房.街连街.村连村的地下工事,如下图所示. 我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智. ...