三、curator recipes之共享的可重入读写锁
简介
curator实现了跨JVM的可重入读写互斥锁。它使用zookeeper去进行加锁,所以指定相同路径的处理线程将会基于“公平锁”的机制去竞争锁资源。
读写锁包含了读锁、写锁两个,它们的互斥关系如下:
1)读写互斥;
2)写写互斥;
3)读读不互斥。
重入性:读写锁是可以重入的,意味着你获取了一次读锁/写锁,那么你可以再次获取。但是要记得最后释放锁,获取了几次就得释放几次。
降级/升级:写锁可以降级成读锁,但是读锁不能升级成写锁否则会导致循环等待最终死锁。
官方文档:http://curator.apache.org/curator-recipes/shared-reentrant-read-write-lock.html
相关接口:InterProcessLock
实现类:InterProcessReadWriteLock
依赖
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency>
示例
import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.locks.InterProcessMutex; import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock; import org.apache.curator.retry.ExponentialBackoffRetry; public class LocksDemo { private static CuratorFramework client; private static InterProcessMutex readLock; private static InterProcessMutex writeLock; static { client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181").retryPolicy(new ExponentialBackoffRetry(3000, 1)).build(); // 调用启动 client.start(); // 获取读写锁 InterProcessReadWriteLock lock = new InterProcessReadWriteLock(client, "/user"); readLock = lock.readLock(); writeLock = lock.writeLock(); } public static void main(String[] args) throws Exception { new Thread(new Runnable() { public void run() { System.out.println("线程1启动"); try { // 先获取读锁 readLock.acquire(); System.out.println("获取读锁" + System.currentTimeMillis()); Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } finally { try { // 释放读锁 readLock.release(); System.out.println("释放读锁" + System.currentTimeMillis()); } catch (Exception e) { e.printStackTrace(); } } } }).start(); System.out.println("主线程休眠2秒,让子线程获取读锁"); Thread.sleep(2000); // 争抢写锁,这时候读锁还没有释放 writeLock.acquire(); // 3秒钟以后,读锁释放了,写锁获取,最终写锁也释放 System.out.println("获取写锁" + System.currentTimeMillis()); writeLock.release(); System.out.println("释放写锁" + System.currentTimeMillis()); // 最后关闭 client.close(); } }
我们先拿到一个framework,然后创建一个InterProcessReadWriteLock,就可以通过它拿到读写锁实例对象了。
在代码中,子线程获取了读锁,然后休眠3秒,而主线程这期间想要获取写锁,就得阻塞等待读锁释放,然后才能获取写锁。