1.zookeeper分布式锁
1.1分布式锁方式一:
所有实例都注册到同一个节点上去,成功的加锁,不成功的失败,当一个解锁后删除该节点,监听该节点的所有实例就会去抢锁,这就导致所有的都要去抢。
以下代码解析:
package com.study.mike.zookeeper;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
public class ZKDistributeLock implements Lock {
private String lockPath;
private ZkClient client;
// 锁重入计数
private ThreadLocal<Integer> reentrantCount = new ThreadLocal<>();
public ZKDistributeLock(String lockPath) {
super();
this.lockPath = lockPath;
client = new ZkClient("localhost:2181");
client.setZkSerializer(new MyZkSerializer());
}
@Override
public boolean tryLock() { // 不会阻塞
//重入锁存在加一,不存在设置为1
if (this.reentrantCount.get() != null) {
int count = this.reentrantCount.get();
if (count > 0) {
this.reentrantCount.set(++count);
System.out.println(Thread.currentThread().getName() + " 尝试加锁成功!"+count);
return true;
}
}
// 创建节点
try {
client.createEphemeral(lockPath);
this.reentrantCount.set(1);
} catch (ZkNodeExistsException e) {
System.out.println(Thread.currentThread().getName() + " 尝试加锁失败!");
return false;
}
System.out.println(Thread.currentThread().getName() + " 尝试加锁成功!");
return true;
}
@Override
public void unlock() {
// 重入的释放锁处理
if (this.reentrantCount.get() != null) {
int count = this.reentrantCount.get();
if (count > 1) {
this.reentrantCount.set(--count);
return;
} else {
this.reentrantCount.set(null);
}
}
client.delete(lockPath);
}
@Override
public void lock() { // 如果获取不到锁,阻塞等待
if (!tryLock()) {
// 没获得锁,阻塞自己
waitForLock();
// 再次尝试
lock();
}
}
private void waitForLock() {
CountDownLatch cdl = new CountDownLatch(1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("----收到节点被删除了-------------");
cdl.countDown();
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
}
};
client.subscribeDataChanges(lockPath, listener);
// 阻塞自己
if (this.client.exists(lockPath)) {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 取消注册
client.unsubscribeDataChanges(lockPath, listener);
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO Auto-generated method stub
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO Auto-generated method stub
return false;
}
@Override
public Condition newCondition() {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) {
// 并发数
int currency = 50;
// 循环屏障
CyclicBarrier cb = new CyclicBarrier(currency);
// 多线程模拟高并发
for (int i = 0; i < currency; i++) {
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "---------我准备好---------------");
// 等待一起出发
try {
cb.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
ZKDistributeLock lock = new ZKDistributeLock("/distLock11");
try {
lock.lock();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 获得锁!");
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 释放锁成功!");
}
}
}).start();
}
}
}
1.2分布式锁二:
方式二,下面一个节点只注册监听前面一个节点,解决了惊群效应。其子节点按照顺序排序:
其代码如下:
package com.study.mike.zookeeper;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
public class ZKDistributeImproveLock implements Lock {
/*
* 利用临时顺序节点来实现分布式锁
* 获取锁:取排队号(创建自己的临时顺序节点),然后判断自己是否是最小号,如是,则获得锁;不是,则注册前一节点的watcher,阻塞等待
* 释放锁:删除自己创建的临时顺序节点
*/
private String lockPath;
private ZkClient client;
private ThreadLocal<String> currentPath = new ThreadLocal<>();
private ThreadLocal<String> beforePath = new ThreadLocal<>();
// 锁重入计数
private ThreadLocal<Integer> reentrantCount = new ThreadLocal<>();
public ZKDistributeImproveLock(String lockPath) {
super();
this.lockPath = lockPath;
client = new ZkClient("localhost:2181");
client.setZkSerializer(new MyZkSerializer());
if (!this.client.exists(lockPath)) {
try {
this.client.createPersistent(lockPath);
} catch (ZkNodeExistsException e) {
}
}
}
@Override
public boolean tryLock() {
System.out.println(Thread.currentThread().getName()+"this.reentrantCount.get() " +this.reentrantCount.get()+"(this.currentPath.get() "+(this.currentPath.get() ));
if (this.reentrantCount.get() != null) {
int count = this.reentrantCount.get();
if (count > 0) {
this.reentrantCount.set(++count);
System.out.println(Thread.currentThread().getName() + " 尝试加锁成功!"+count);
return true;
}
}
if (this.currentPath.get() == null) {
currentPath.set(this.client.createEphemeralSequential(lockPath + "/", "aaa"));
System.out.println(Thread.currentThread().getName() + " this.currentPath.get()"+this.currentPath.get());
}
// 获得所有的子
List<String> children = this.client.getChildren(lockPath);
// 排序list
Collections.sort(children);
// 判断当前节点是否是最小的
if (currentPath.get().equals(lockPath + "/" + children.get(0))) {
this.reentrantCount.set(1);
System.out.println(Thread.currentThread().getName() + " 尝试加锁成功!判断当前节点是否是最小的");
return true;
} else {
// 取到前一个
// 得到字节的索引号
int curIndex = children.indexOf(currentPath.get().substring(lockPath.length() + 1));
beforePath.set(lockPath + "/" + children.get(curIndex - 1));
}
System.out.println(Thread.currentThread().getName() + " 尝试加锁失败!"+beforePath.get());
return false;
}
@Override
public void lock() {
if (!tryLock()) {
// 阻塞等待
waitForLock();
// 再次尝试加锁
lock();
}
}
private void waitForLock() {
CountDownLatch cdl = new CountDownLatch(1);
// 注册watcher
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("-----监听到节点被删除"+dataPath);
Thread.sleep(60000);
cdl.countDown();
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println(dataPath+"-----监听到节点数据"+data );
}
};
client.subscribeDataChanges(this.beforePath.get(), listener);
// 怎么让自己阻塞
if (this.client.exists(this.beforePath.get())) {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 醒来后,取消watcher
client.unsubscribeDataChanges(this.beforePath.get(), listener);
}
@Override
public void unlock() {
// 重入的释放锁处理
if (this.reentrantCount.get() != null) {
int count = this.reentrantCount.get();
if (count > 1) {
this.reentrantCount.set(--count);
return;
} else {
this.reentrantCount.set(null);
}
}
// 删除节点
this.client.delete(this.currentPath.get());
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO Auto-generated method stub
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO Auto-generated method stub
return false;
}
@Override
public Condition newCondition() {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) {
// 并发数
int currency = 50;
// 循环屏障
CyclicBarrier cb = new CyclicBarrier(currency);
// 多线程模拟高并发
for (int i = 0; i < currency; i++) {
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "---------我准备好---------------");
// 等待一起出发
try {
cb.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
ZKDistributeImproveLock lock = new ZKDistributeImproveLock("/distLock");
try {
lock.lock();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 获得锁!");
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 释放锁成功!");
}
}
}).start();
}
}
}
2.redis分布式锁
package com.newland.paas.paasservice.scheduled.job.core;
import com.newland.paas.log.LogProperty;
import com.newland.paas.nai.datamodule.enums.RedisKeyEnum;
import com.newland.paas.sbcommon.utils.SpringContextUtil;
import org.redisson.Redisson;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RQueue;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import redis.clients.jedis.Jedis;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
public class RedissionLock {
private RedissonClient redisson;
private static final String TASK_FLOW_EXEC_REQUEST = "taskFlowExecRequest";
private static final String TASK_FLOW_STOP_REQUEST = "taskFlowStopRequest";
private static final String NODE_HEARTBEAT = "nodeHeartbeat";
private String getTaskFlowExecRequest() {
String profile ="dev" + ":";
return profile + TASK_FLOW_EXEC_REQUEST;
}
private String getTaskFlowStopRequest() {
String profile ="dev" + ":";
return profile + TASK_FLOW_STOP_REQUEST;
}
public RedissionLock(){
//创建配置
Config config = new Config();
//指定编码,默认编码为org.redisson.codec.JsonJacksonCodec
config.setCodec(new org.redisson.client.codec.StringCodec());
//指定使用单节点部署方式
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// config.useSingleServer().setClientName("root");
// config.useSingleServer().setPassword("abcabc");
//创建redisson客户端
redisson = Redisson.create(config);
RBucket<String> keyObject = redisson.getBucket("key");
keyObject.set("value");
System.out.println("连接成功");
}
public void lock(String name) {
RLock lock = redisson.getLock(name);
lock.lock();
}
public void lock(String name, long leaseTime, TimeUnit unit) {
if(tryLock(name,60,leaseTime,unit)) {
RLock lock = redisson.getLock(name);
lock.lock(leaseTime, unit);
}
}
public boolean tryLock(String name, long waitTime, long leaseTime, TimeUnit unit) {
RLock lock = redisson.getLock(name);
boolean res = false;
try {
res = lock.tryLock(waitTime, leaseTime, unit);
} catch (Exception e) {
System.out.println("尝试获取锁异常!" + e.getMessage());
}
if(res==false){
System.out.println(Thread.currentThread().getName()+"尝试加锁失败!" +res) ;
}else {
System.out.println(Thread.currentThread().getName() + "尝试加锁成功!" + res);
}
return res;
}
public void unlock(String name) {
RLock lock = redisson.getLock(name);
lock.unlock();
}
public boolean execRequestOffer(String request) {
String taskFlowExecRequest = this.getTaskFlowExecRequest();
RQueue<String> queue = redisson.getQueue(taskFlowExecRequest);
return queue.offer(request);
}
public String execRequestPoll() {
String taskFlowExecRequest = this.getTaskFlowExecRequest();
RQueue<String> queue = redisson.getQueue(taskFlowExecRequest);
return queue.poll();
}
public void stopRequestAdd(Long logId) {
String taskFlowStopRequest = this.getTaskFlowStopRequest();
RAtomicLong stopRequest = redisson.getAtomicLong(taskFlowStopRequest + ":" + logId);
stopRequest.set(logId);
}
public Boolean stopRequestContains(Long logId) {
String taskFlowStopRequest = this.getTaskFlowStopRequest();
RAtomicLong stopRequest = redisson.getAtomicLong(taskFlowStopRequest + ":" + logId);
if (stopRequest != null && stopRequest.get() == logId) {
return true;
}
return false;
}
public void stopRequestRemove(Long logId) {
String taskFlowStopRequest = this.getTaskFlowStopRequest();
RAtomicLong stopRequest = redisson.getAtomicLong(taskFlowStopRequest + ":" + logId);
if (stopRequest != null) {
stopRequest.delete();
}
}
public static void main(String[] args) {
RedissionLock lock = new RedissionLock();
// 并发数
int currency = 50;
// 循环屏障
CyclicBarrier cb = new CyclicBarrier(currency);
// 多线程模拟高并发
for (int i = 0; i < currency; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "---------我准备好---------------");
// 等待一起出发
try {
cb.await();
lock.execRequestOffer("输入当前线程"+Thread.currentThread().getName());
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
while(true) {
RQueue queue = lock.redisson.getQueue(lock.getTaskFlowExecRequest());
System.out.println("总队列大小"+queue.size());
if (queue.size() > 0) {
try {
Boolean flag = lock.tryLock("lockKey", 1, 1, TimeUnit.SECONDS);
if (flag) {
System.out.println(Thread.currentThread().getName() + " 获得锁!");
String request = lock.execRequestPoll();
System.out.println(Thread.currentThread().getName() + " 取出队列数据!" + request);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock("lockKey");
System.out.println(Thread.currentThread().getName() + " 释放锁成功!");
}
} finally {
/* lock.unlock("lockKey");
System.out.println(Thread.currentThread().getName() + " 释放锁成功!");
*/
}
}
}
}
}
}