面向過程版:
package distributedLockProcess;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class dl {
private static final Logger LOG = LoggerFactory.getLogger(dl.class);
//確保所有線程運行結束;
private static final String CONNECTION_STRING = "192.168.1.201:2181,192.168.1.202:2181,192.168.1.203:2181";
private static final int SESSION_TIMEOUT = 10000;
private static final String GROUP_PATH = "/disLocks";
private static final String SUB_PATH = "/disLocks/sub";
private static final int THREAD_NUM = 10;
public static CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
public static void main(String[] args) {
for(int i=0; i < THREAD_NUM; i++){
final int threadId = i;
new Thread(){
@Override
public void run() {
final CountDownLatch countDownLatch = new CountDownLatch(1);
try{
//此線程連接ZooKeeper
ZooKeeper zk = new ZooKeeper(CONNECTION_STRING, SESSION_TIMEOUT, new Watcher(){
@Override
public void process(WatchedEvent event){
if (event.getState() == KeeperState.SyncConnected){
countDownLatch.countDown();
}
}
});
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + " --- ZooKeeper.connect()");
//GROUP_PATH不存在的話,由一個線程創建即可;
if(zk.exists(GROUP_PATH, false)==null){
LOG.info( Thread.currentThread().getName() + "節點創建成功, Path: "
+ zk.create( GROUP_PATH,
("該節點由線程"+Thread.currentThread().getName() + "創建").getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT )
+ ", content: " + ("該節點由線程"+Thread.currentThread().getName() + "創建") );
}
String selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
LOG.info(Thread.currentThread().getName()+"創建鎖路徑:"+selfPath);
if(checkMinPath(zk, selfPath)){
LOG.info(Thread.currentThread().getName() + "獲取鎖成功,趕緊幹活!");
dosomething();
threadSemaphore.countDown();
try {
if(zk.exists(selfPath,false) == null){
LOG.error(Thread.currentThread().getName()+"本節點已不在了...");
return;
}
zk.delete(selfPath, -1);
LOG.info(Thread.currentThread().getName() + "刪除本節點:"+selfPath);
zk.close();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (Exception e){
LOG.error("【第"+threadId+"個線程】 拋出的異常:");
e.printStackTrace();
}
}
}.start();
}
try {
// Thread.sleep(60000);
threadSemaphore.await();
LOG.info("所有線程運行結束!");
} catch (Exception e) {
e.printStackTrace();
}
}
protected static boolean checkMinPath(final ZooKeeper zk, final String selfPath) throws KeeperException, InterruptedException {
List<String> subNodes = zk.getChildren(GROUP_PATH, false);
Collections.sort(subNodes);
int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
switch (index){
case -1:{
LOG.error(Thread.currentThread().getName()+"本節點已不在了..."+selfPath);
return false;
}
case 0:{
LOG.info(Thread.currentThread().getName()+"子節點中,我果然是老大"+selfPath);
return true;
}
default:{
final String waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
LOG.info(Thread.currentThread().getName()+"獲取子節點中,排在我前面的"+waitPath);
try{
zk.getData(waitPath, new Watcher(){
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
LOG.info(Thread.currentThread().getName()+ "收到情報,排我前面的傢伙已掛,我是不是可以出山了?");
try {
if(checkMinPath(zk, selfPath)){
LOG.info(Thread.currentThread().getName() + "獲取鎖成功,趕緊幹活!");
dosomething();
threadSemaphore.countDown();
try {
if(zk.exists(selfPath,false) == null){
LOG.error(Thread.currentThread().getName()+"本節點已不在了...");
} else {
zk.delete(selfPath, -1);
LOG.info(Thread.currentThread().getName() + "刪除本節點:"+selfPath);
zk.close();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch ( Exception e) {
e.printStackTrace();
}
}
}
}, new Stat());
}catch(KeeperException e){
if(zk.exists(waitPath,false) == null){
LOG.info(Thread.currentThread().getName()+"子節點中,排在我前面的"+waitPath+"已失蹤,幸福來得太突然?");
return checkMinPath(zk, selfPath);
}else{
throw e;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}
protected static void dosomething() {
System.out.println("我正在獨享資源互斥地進行工作。。。");
}
}
面向對象重構版:
package distributedLockObject;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
public class AbstractZooKeeper implements Watcher{
protected ZooKeeper zookeeper;
protected CountDownLatch countDownLatch = new CountDownLatch(1);
public ZooKeeper connect(String hosts, int SESSION_TIMEOUT) throws IOException, InterruptedException{
zookeeper = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
countDownLatch.await();
System.out.println("AbstractZooKeeper.connect()");
return zookeeper;
}
public void process(WatchedEvent event){
if (event.getState() == KeeperState.SyncConnected){
countDownLatch.countDown();
}
}
public void close() throws InterruptedException{
zookeeper.close();
}
}
package distributedLockObject;
import java.util.Collections;
import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DistributedLock {
private ZooKeeper zk = null;
private String selfPath;
private String waitPath;
private String LOG_PREFIX_OF_THREAD=Thread.currentThread().getName();
private static final String GROUP_PATH = "/disLocks";
private static final String SUB_PATH = "/disLocks/sub";
private static final Logger LOG = LoggerFactory.getLogger(DistributedLock.class);
private Watcher watcher;
public DistributedLock(ZooKeeper zk ) {
this.zk = zk;
}
public Watcher getWatcher() {
return watcher;
}
public void setWatcher(Watcher watcher) {
this.watcher = watcher;
}
/**
* 獲取鎖
* @return
*/
public boolean getLock() throws KeeperException, InterruptedException {
selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
LOG.info(LOG_PREFIX_OF_THREAD+"創建鎖路徑:"+selfPath);
if(checkMinPath()){
return true;
}
return false;
}
/**
* 創建節點
* @param path 節點path
* @param data 初始數據內容
* @return
*/
public boolean createPath( String path, String data ) throws KeeperException, InterruptedException {
if(zk.exists(path, false)==null){
LOG.info( LOG_PREFIX_OF_THREAD + "節點創建成功, Path: "
+ this.zk.create( path,
data.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT )
+ ", content: " + data );
}
return true;
}
public void unlock(){
try {
if(zk.exists(this.selfPath,false) == null){
LOG.error(LOG_PREFIX_OF_THREAD+"本節點已不在了...");
return;
}
zk.delete(this.selfPath, -1);
LOG.info(LOG_PREFIX_OF_THREAD + "刪除本節點:"+selfPath);
zk.close();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 檢查自己是不是最小的節點
* @return
*/
public boolean checkMinPath() throws KeeperException, InterruptedException {
List<String> subNodes = zk.getChildren(GROUP_PATH, false);
Collections.sort(subNodes);
int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
switch (index){
case -1:{
LOG.error(LOG_PREFIX_OF_THREAD+"本節點已不在了..."+selfPath);
return false;
}
case 0:{
LOG.info(LOG_PREFIX_OF_THREAD+"子節點中,我果然是老大"+selfPath);
return true;
}
default:{
this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
LOG.info(LOG_PREFIX_OF_THREAD+"獲取子節點中,排在我前面的"+waitPath);
try{
zk.getData(waitPath, this.watcher, new Stat());
return false;
}catch(KeeperException e){
if(zk.exists(waitPath,false) == null){
LOG.info(LOG_PREFIX_OF_THREAD+"子節點中,排在我前面的"+waitPath+"已失蹤,幸福來得太突然?");
return checkMinPath();
}else{
throw e;
}
}
}
}
}
public String getWaitPath() {
return waitPath;
}
}
package distributedLockObject;
public interface DoTemplate {
void dodo();
}
package distributedLockObject;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
public class LockService {
//確保所有線程運行結束;
private static final String CONNECTION_STRING = "192.168.1.201:2181,192.168.1.202:2181,192.168.1.203:2181";
private static final int THREAD_NUM = 10;
public static CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
private static final String GROUP_PATH = "/disLocks";
private static final int SESSION_TIMEOUT = 10000;
AbstractZooKeeper az = new AbstractZooKeeper();
public void doService(DoTemplate doTemplate){
try {
ZooKeeper zk = az.connect(CONNECTION_STRING,SESSION_TIMEOUT);
DistributedLock dc = new DistributedLock(zk);
LockWatcher lw = new LockWatcher(dc,doTemplate);
dc.setWatcher(lw);
//GROUP_PATH不存在的話,由一個線程創建即可;
dc.createPath(GROUP_PATH, "該節點由線程"+Thread.currentThread().getName() + "創建");
boolean rs = dc.getLock();
if (rs==true) {
lw.dosomething();
dc.unlock();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package distributedLockObject;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LockWatcher implements Watcher{
private static final Logger LOG = LoggerFactory.getLogger(LockWatcher.class);
private DistributedLock distributedLock;
private DoTemplate doTemplate;
public LockWatcher(DistributedLock distributedLock,DoTemplate doTemplate) {
// TODO Auto-generated constructor stub
this.distributedLock = distributedLock;
this.doTemplate = doTemplate;
}
@Override
public void process(WatchedEvent event) {
// TODO Auto-generated method stub
if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(distributedLock.getWaitPath())) {
LOG.info(Thread.currentThread().getName()+ "收到情報,排我前面的傢伙已掛,我是不是可以出山了?");
try {
if(distributedLock.checkMinPath()){
dosomething();
distributedLock.unlock();
}
} catch ( Exception e) {
e.printStackTrace();
}
}
}
public void dosomething(){
LOG.info(Thread.currentThread().getName() + "獲取鎖成功,趕緊幹活!");
doTemplate.dodo();
TestLock.threadSemaphore.countDown();
}
}
package distributedLockObject;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestLock {
private static final Logger LOG = LoggerFactory.getLogger(TestLock.class);
//確保所有線程運行結束;
private static final int THREAD_NUM = 10;
public static CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
public static void main(String[] args) {
for(int i=0; i < THREAD_NUM; i++){
final int threadId = i;
new Thread(){
@Override
public void run() {
try{
new LockService().doService(new DoTemplate() {
@Override
public void dodo() {
// TODO Auto-generated method stub
LOG.info("我要修改一個文件。。。。"+threadId);
}
});
} catch (Exception e){
LOG.error("【第"+threadId+"個線程】 拋出的異常:");
e.printStackTrace();
}
}
}.start();
}
try {
// Thread.sleep(60000);
threadSemaphore.await();
LOG.info("所有線程運行結束!");
} catch (Exception e) {
e.printStackTrace();
}
}
}