传统单体项目情况下,要实现锁可直接通过java提供的关键字,或者工具类实现。但在分布式情况下,就需要借助外部工具,如redis,zk等。
下面介绍一种通过zk实现的分布式锁。
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;
public class CuratorDemo {
public static void main(String[] args) throws Exception {
//操作失败重试机制 1000毫秒间隔 重试3次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
//创建Curator客户端
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.1.18:2181", retryPolicy);
//开始
client.start();
/**
* 这个类是线程安全的,一个JVM创建一个就好
* mylock 为锁的根目录,我们可以针对不同的业务创建不同的根目录
*/
final InterProcessMutex lock = new InterProcessMutex(client, "/mylock");
try {
//阻塞方法,获取不到锁线程会挂起。
lock.acquire();
System.out.println("已经获取到锁");
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
finally{
//释放锁,必须要放到finally里面,已确保上面方法出现异常时也能够释放锁。
lock.release();
}
Thread.sleep(10000);
client.close();
}
}
模拟多个客户端
public class CuratorDemo {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
//启动10个线程模拟多个客户端
Jvmlock jl = new Jvmlock(i);
new Thread(jl).start();
//这里加上300毫秒是为了让线程按顺序启动,不然有可能4号线程比3号线程先启动了,这样测试就不准了。
Thread.sleep(300);
}
}
public static class Jvmlock implements Runnable{
private int num;
public Jvmlock(int num) {
this.num = num;
}
@Override
public void run() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory
.newClient("192.168.142.128:2181", retryPolicy);
client.start();
InterProcessMutex lock = new InterProcessMutex(client,
"/mylock");
try {
System.out.println("我是第" + num + "号线程,我开始获取锁");
lock.acquire();
System.out.println("我是第" + num + "号线程,我已经获取锁");
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
client.close();
}
}
}
打印结果
如果是要控制api接口的话,可以借助注解,aspect等方式进行控制。