背景:這是一個老生長談的問題了,能夠用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(); }