https://blog.csdn.net/u012152619/article/category/6470028
目前zookeeper常用的开发包有zkclient跟curator,后者更为方便,日常开发使用较多。
1. 分布式锁:
public class Test {
private static final String HOST = "localhost:2181";
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
ZkClient zkClient = new ZkClient(HOST, 5000, 5000, new SerializableSerializer());
Resources resources = new Resources();
Runnable finishTask = new FinishTask(resources);
CyclicBarrier barrier = new CyclicBarrier(10, finishTask);
for(int i = 0; i < 10; i++){
Task t = new Task(zkClient, resources, barrier, "test" + i);
t.start();
}
}
}
public class Resources {
private int count;
public int plus(){
try {
Thread.sleep(1000l);
count++;
System.out.println(Thread.currentThread().getName() + " 当前count值为 : " + count);
} catch (InterruptedException e) {
e.printStackTrace();
}
return count;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public class FinishTask implements Runnable{
private Resources resources;
public FinishTask(Resources resources){
this.resources = resources;
}
@Override
public void run() {
System.out.println("操作完成 ! count : " + resources.getCount());
}
}
public class Task extends Thread{
private static final String LOCK_ROOT_PATH = "/lock";
private Resources resources;
private CyclicBarrier barrier;
private ZkClient zkClient;
public Task(ZkClient zkClient, Resources resources, CyclicBarrier barrier, String name) {
this.zkClient = zkClient;
this.resources = resources;
this.barrier = barrier;
super.setName(name);
}
@Override
public void run() {
String path = this.getLock();
resources.plus();
releaseLock(path);
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
private void releaseLock(String path) {
zkClient.delete(path, -1);
}
private String getLock() {
String path = RegisterNode();
try {
tryLock(path);
} catch (InterruptedException e) {
e.printStackTrace();
}
return path;
}
private boolean tryLock(String path) throws InterruptedException {
List<String> lockPaths = zkClient.getChildren(LOCK_ROOT_PATH);
Collections.sort(lockPaths);
int index = lockPaths.indexOf(path.substring(LOCK_ROOT_PATH.length() + 1));
if (index == 0) {
System.out.println(this.getName() + " get lock, lockPath: " + path);
return true;
} else {
String preLockPath = lockPaths.get(index - 1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String watcherPath) throws Exception {
System.out.println(watcherPath + " has been deleted");
synchronized(this){
this.notifyAll();
}
}
@Override
public void handleDataChange(String path, Object data) {
}
};
boolean exist = zkClient.exists(LOCK_ROOT_PATH + "/" + preLockPath);
if (!exist) {
return tryLock(path);
} else {
zkClient.subscribeDataChanges(LOCK_ROOT_PATH + "/" + preLockPath, listener);
System.out.println(Thread.currentThread().getName() + " wait for " + preLockPath);
synchronized(listener){
listener.wait();
}
return tryLock(path);
}
}
}
private String RegisterNode(){
String path = zkClient.create(LOCK_ROOT_PATH + "/lock_", super.getName(), CreateMode.EPHEMERAL_SEQUENTIAL);
return path;
}
2. 队列
public class Test {
public static void main(String[] args) {
final ZkBlockingQueue queue = new ZkBlockingQueue(8, "queue");
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i <= 1000; i++){
queue.put(""+i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i <= 1000; i++){
queue.take();
}
}
}).start();
}
}
public class ZkBlockingQueue {
private static final String HOST = "localhost:2181";
private static final String QUEUE_ROOT_PATH = "/queue";
private final int MAX_STORE_SIZE;
private Producer producer;
private Customer customer;
public ZkBlockingQueue(int max, String name){
MAX_STORE_SIZE = max;
producer = new Producer(this);
customer = new Customer(this);
}
public void put(String s){
producer.put(s);
}
public String take(){
return customer.take();
}
public class Producer{
private ZkClient zkClient;
private ZkBlockingQueue queue;
public Producer(ZkBlockingQueue zkBlockingQueue){
this.zkClient = new ZkClient(HOST, 5000, 5000, new SerializableSerializer());
queue = zkBlockingQueue;
}
private void put(final String s) {
while(true){
int size = zkClient.countChildren(QUEUE_ROOT_PATH);
if(size != queue.MAX_STORE_SIZE){
String path = RegisterNode(s);
System.out.println( "create path : " + path + " value : " + s);
break;
}else{
System.out.println("queue is full !");
IZkChildListener listener = new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds)
throws Exception {
if(currentChilds.size() < queue.MAX_STORE_SIZE){
synchronized (this) {
this.notify();
}
}
}
};
zkClient.subscribeChildChanges(QUEUE_ROOT_PATH, listener);
synchronized (listener) {
try {
listener.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
private String RegisterNode(String s){
String path = zkClient.create(QUEUE_ROOT_PATH + "/number_", s, CreateMode.EPHEMERAL_SEQUENTIAL);
return path;
}
}
public class Customer{
private ZkClient zkClient;
public Customer(ZkBlockingQueue zkBlockingQueue){
this.zkClient = new ZkClient(HOST, 5000, 5000, new SerializableSerializer());
}
private String take() {
while(true){
int size = zkClient.countChildren(QUEUE_ROOT_PATH);
if(size != 0){
List<String> lockPaths = zkClient.getChildren(QUEUE_ROOT_PATH);
Collections.sort(lockPaths);
String value = takeNode("/" + lockPaths.get(0));
System.out.println("get data : " + value);
return value;
}else{
System.out.println("queue is empty !");
IZkChildListener listener = new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds)
throws Exception {
if(currentChilds.size() > 0){
this.notifyAll();
}
}
};
zkClient.subscribeChildChanges(QUEUE_ROOT_PATH, listener);
synchronized(listener){
try {
listener.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
private String takeNode(String path){
String value = zkClient.readData(QUEUE_ROOT_PATH + path);
zkClient.delete(QUEUE_ROOT_PATH + path);
return value;
}
}
}
3. 应用主备,主从
所有服务器同时会在servers节点下注册一个临时节点。
servers节点下所有服务争抢在zookeeper中注册master节点,未竞争成功者在zookeeper注册监听,若主服务失去连接,再次竞争。