背景:这是一个老生长谈的问题了,能够用redis、数据库、zookeeper。这里今天就用zookeeper来实现下。java
这个版本也是参考CSDN公众号来实现的,原理很简单:只要利用apache curator封装后的client直接链接zk server,获取锁就好了。步骤以下:git
一、安装好zk3.5单机版redis
二、配置一下pom(国外的maven仓库链接不上,配置阿里云的maven仓库)数据库
三、运行java代码apache
package hello; import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.locks.InterProcessMutex; import org.apache.curator.retry.ExponentialBackoffRetry; /** * Created by Germmy on 2017/11/4. */ public class MyClient { public static void main(String[] args) { try { //建立zookeeper的客户端 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.92.134:2181", retryPolicy); client.start(); //建立分布式锁, 锁空间的根节点路径为/curator/lock InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock"); mutex.acquire(); //得到了锁, 进行业务流程 System.out.println("Enter mutex"); //完成业务流程, 释放锁 mutex.release(); //关闭客户端 client.close(); } catch (Exception e) { e.printStackTrace(); } } }
注意:apche curator必须用在3.5版本上的zk,不然会报unimplement异常,curator官方说兼容3.4.X,但实际上呵呵了windows
四、编写一个客户端来试,这个客户端就是负责将它一个变量自增,那么在多个线程全在操做这个客户端时,是否会发生线程安全问题呢?安全
4.一、先用非线程安全的客户端试下,源码以下:maven
package hello; /** * Created by Germmy on 2017/11/5. */ public class MyClientNotSafe implements Runnable { public static int num=0; public void run() { num++; System.out.println("当前线程ID是:"+Thread.currentThread().getId()+",数字是:"+num); } }
线程池的源码以下:分布式
@Test public void testNumPlusNoSafe(){ ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++){ executorService.execute(new MyClientNotSafe()); } executorService.shutdown(); }
输出结果以下:测试
发现有2个结果全是2,线程不安全。
4.二、用分布式锁的客户端锁试下,客户端源码以下:
package hello; import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.locks.InterProcessMutex; import org.apache.curator.retry.ExponentialBackoffRetry; /** * Created by Germmy on 2017/11/4. */ public class MyClient implements Runnable { public static int num=0; public void run(){ System.out.println("进入了MyClient1..."); try { System.out.println("进入了MyClient2..."); //建立zookeeper的客户端 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.92.135:2181", retryPolicy); client.start(); //建立分布式锁, 锁空间的根节点路径为/curator/lock InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock"); mutex.acquire(); //得到了锁, 进行业务流程 num++; System.out.println("当前线程ID是:"+Thread.currentThread().getId()+",数字是:"+num); //完成业务流程, 释放锁 mutex.release(); //关闭客户端 client.close(); } catch (Exception e) { e.printStackTrace(); } } }
测试代码以下:
public static void main(String args[]){ ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++){ executorService.execute(new MyClient()); } executorService.shutdown(); }