根据不同的场景来选择不同的方式,一下案例只保证数据一致性.....具体的要根据具体的应用场景来分析
1.分布式锁常用的几种实现
在分析这几种实现方案之前我们先来想一下,我们需要的分布式锁应该是怎么样的?(这里以方法锁为例,资源锁同理)
可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。
这把锁要是一把可重入锁(避免死锁)
这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
有高可用的获取锁和释放锁功能
获取锁和释放锁的性能要好
什么是可重入锁和不可重入锁?
https://www.cnblogs.com/dj3839/p/6580765.html 懒得写了...这篇写的很清晰
2.分布式锁的具体实现
2.1基于数据库的分布式锁
在数据库里加一个唯一约束字段,每次新增的时候去验证是否是否成功,失败在做异常处理。
可以在数据库里新建一个字段存放当前节点的名称和线程名用来保证可重入性。
2.2 基于zookeeper的分布式锁实现
可以使用JavaApi实现,可以使用zkClient实现,可以使用curator实现,curator的功能十分强大,封装了很多应用场景中常见的例子,例如master选举和分布式锁。
2.21 基于zkClient的实现
ZkClient工具类
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
public class ZookeeperClient {
private final static String CONNECTSTRING="192.168.154.130:2181,192.168.154.130:2182,192.168.154.130:2183" ;
private static int sessionTimeout=5000;
//获取连接
public static ZooKeeper getInstance() throws IOException, InterruptedException {
final CountDownLatch conectStatus=new CountDownLatch(1);
ZooKeeper zooKeeper=new ZooKeeper(CONNECTSTRING, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
if(event.getState()== Event.KeeperState.SyncConnected){
conectStatus.countDown();
}
}
});
conectStatus.await();
return zooKeeper;
}
public static int getSessionTimeout() {
return sessionTimeout;
}
}
zkClient分布式锁的实现
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.List;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
public class DistributeLock {
//根节点
private static final String ROOT_LOCK="/Locks2";
private ZooKeeper zooKeeper;
private int SessionTimeOut;
private static final byte[] data={1,2};
private String LockId;//记录锁的Id
private CountDownLatch countDownLatch = new CountDownLatch(1);
public DistributeLock(){
try {
this.zooKeeper = ZookeeperClient.getInstance();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.SessionTimeOut = ZookeeperClient.getSessionTimeOut();
}
//获取锁的方法
public boolean lock(){
try {
//创建一个临时有序节点
LockId = zooKeeper.create(ROOT_LOCK+"/",data,ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(Thread.currentThread().getName()+"成功的创建了lockId:"+LockId);
//获取根节点所有子节点
List<String> rootNodes = zooKeeper.getChildren(ROOT_LOCK,true);
//排序
SortedSet<String> sortedSet = new TreeSet();
rootNodes.forEach(s -> sortedSet.add(ROOT_LOCK+"/"+s));
String first = sortedSet.first();
//成功获取锁
if(LockId.equals(first)){
System.out.println(Thread.currentThread().getName()+"->我拿到了锁->lock:"+LockId);
return true;
}
//获取比它小的节点
SortedSet<String> lessSortedSet = sortedSet.headSet(LockId);
CountDownLatch countDownLatch1 = new CountDownLatch(1);
if(!lessSortedSet.isEmpty()){
String prevLockId = lessSortedSet.last();//拿到比当前LOCKID这个节点更小的上一个节点
zooKeeper.exists(prevLockId, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
if(watchedEvent.getType()==Event.EventType.NodeDeleted){
countDownLatch1.countDown();
}
}
});
countDownLatch1.await(SessionTimeOut,TimeUnit.MILLISECONDS);
//上面节点删除或者释放
System.out.println(Thread.currentThread().getName()+"成功获取锁:"+LockId);
}
return true;
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
public boolean unlock(){
System.out.println(Thread.currentThread().getName()+"-->开始释放锁:"+LockId);
try {
zooKeeper.delete(LockId,-1);
System.out.println("节点:"+LockId+"成功删除");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
return false;
}
}
测试,测试是测的多线程环境,实际应该在多进程环境 ,可以启动多次来进行模拟。
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Unit test for simple App.
*/
public class AppTest
{
public static int count = 0;
public static CountDownLatch countDownLatch = new CountDownLatch(100);
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<100;i++){
DistributeLock distributeLock = new DistributeLock();
Thread thread = new Thread(){
@Override
public void run() {
try {
// distributeLock.lock();
TimeUnit.SECONDS.sleep(1);
for(int y=0;y<200;y++){
count++;
}
/* System.out.println(Thread.currentThread().toString());*/
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// distributeLock.unlock();
}
countDownLatch.countDown();
}
};
thread.start();
}
countDownLatch.await();
System.out.println("结束了-->"+count);
}
}
2.22基于curator的实现
基于curator的就更简单了....推荐看这里---->https://www.jianshu.com/p/31335efec309
代码写的非常详细,对源码也进行了剖析,以下是我的测试.
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class CuratorLocks {
private static CuratorFramework curatorFramework ;
private static int sessionTimeout=5000;
private static final String CONNECTSTRING = "192.168.216.128:2180,192.168.216.128:2181,192.168.216.128:2182";
public static InterProcessMutex getInstance(){
CuratorFramework curatorFramework = CuratorFrameworkFactory.
newClient(CONNECTSTRING,5000,5000,new ExponentialBackoffRetry(1000,3));
curatorFramework.start();
return new InterProcessMutex(curatorFramework,"/locksCurator");
}
}
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMultiLock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 〈一句话功能简述〉<br>
* 〈〉
*
* @author Administrator
* @create 2019/2/22
* @since 1.0.0
*/
public class CuratorTest {
public static int count = 0;
public static CountDownLatch countDownLatch = new CountDownLatch(100);
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<100;i++){
CuratorLocks curatorLocks = new CuratorLocks();
final InterProcessLock interProcessLock = CuratorLocks.getInstance();
Thread thread = new Thread(){
@Override
public void run() {
// distributeLock.lock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
interProcessLock.acquire();
for(int y=0;y<2000;y++){
count++;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
interProcessLock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
countDownLatch.countDown();
}
};
thread.start();
}
countDownLatch.await();
System.out.println("结束了-->"+count);
}
}
2.3基于redis的实现
慢慢在更.....