update at 2021-02-03 23:38:52 by ehlxr
This commit is contained in:
parent
4e43ab53e9
commit
a329e2dea3
0
logs/zkrwlock-error.log
Normal file
0
logs/zkrwlock-error.log
Normal file
403
logs/zkrwlock-server.log
Normal file
403
logs/zkrwlock-server.log
Normal file
File diff suppressed because one or more lines are too long
52
pom.xml
52
pom.xml
@ -2,63 +2,29 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>2.4.2</version>
|
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
|
||||||
</parent>
|
|
||||||
<groupId>io.github.ehlxr</groupId>
|
<groupId>io.github.ehlxr</groupId>
|
||||||
<artifactId>zk-rw-lock</artifactId>
|
<artifactId>zk-rw-lock</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>zk-rw-lock</name>
|
<name>zk-rw-lock</name>
|
||||||
<description>Demo project for Spring Boot</description>
|
<description>Demo project for Spring Boot</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<spring-cloud.version>2020.0.0</spring-cloud.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.apache.curator</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>curator-recipes</artifactId>
|
||||||
</dependency>
|
<version>5.1.0</version>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-dependencies</artifactId>
|
|
||||||
<version>${spring-cloud.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>spring-milestones</id>
|
|
||||||
<name>Spring Milestones</name>
|
|
||||||
<url>https://repo.spring.io/milestone</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.ehlxr.zkrwlock.lockv2;
|
package io.github.ehlxr.zkrwlock;
|
||||||
|
|
||||||
import org.apache.curator.framework.CuratorFramework;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
@ -15,8 +15,8 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* zk 实现读写锁
|
* zk 实现读写锁
|
||||||
* 实现效果为: 在lock 节点下创建 自定义锁资源, lock_01 , lock_02 等
|
* 实现效果为: 在 lock 节点下创建自定义锁资源,如:lock_01,lock_02 等
|
||||||
* 锁资源下为有序临时节点 分为读节点和写节点 read_00001 write_00001
|
* 锁资源下为有序临时节点,分为读节点和写节点,例如:read_00001,write_00001
|
||||||
* 获取读锁的方式为,锁资源下没有写节点,如果有则监听最后一个,读锁之间不会相互竞争
|
* 获取读锁的方式为,锁资源下没有写节点,如果有则监听最后一个,读锁之间不会相互竞争
|
||||||
* 获取写锁的方式也是写锁下没有最后一个节点,并且当前有读锁的时候需要监听当前读锁的结束,写锁之间会相互竞争
|
* 获取写锁的方式也是写锁下没有最后一个节点,并且当前有读锁的时候需要监听当前读锁的结束,写锁之间会相互竞争
|
||||||
*
|
*
|
||||||
@ -40,11 +40,8 @@ public class ZkLock {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
ZK_CLIENT = CuratorFrameworkFactory.builder()
|
ZK_CLIENT = CuratorFrameworkFactory.builder()
|
||||||
// IP 地址 + 端口号,多个用逗号隔开
|
|
||||||
.connectString(SERVER)
|
.connectString(SERVER)
|
||||||
// 会话超时时间
|
|
||||||
.sessionTimeoutMs(TIMEOUT)
|
.sessionTimeoutMs(TIMEOUT)
|
||||||
// 重连机制
|
|
||||||
.retryPolicy(new RetryOneTime(10000))
|
.retryPolicy(new RetryOneTime(10000))
|
||||||
// 命名空间,用该客户端操作的东西都在该节点之下
|
// 命名空间,用该客户端操作的东西都在该节点之下
|
||||||
.namespace(ROOTLOCK)
|
.namespace(ROOTLOCK)
|
||||||
@ -80,8 +77,6 @@ public class ZkLock {
|
|||||||
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
|
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
|
||||||
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
|
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
|
||||||
.forPath("/" + name + "/" + readWriteType.type);
|
.forPath("/" + name + "/" + readWriteType.type);
|
||||||
|
|
||||||
|
|
||||||
attemptLock(path);
|
attemptLock(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +85,6 @@ public class ZkLock {
|
|||||||
ZK_CLIENT.delete()
|
ZK_CLIENT.delete()
|
||||||
.deletingChildrenIfNeeded()
|
.deletingChildrenIfNeeded()
|
||||||
.forPath(path);
|
.forPath(path);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -110,12 +104,11 @@ public class ZkLock {
|
|||||||
.sorted(String::compareTo)
|
.sorted(String::compareTo)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
if (readWriteType == ReadWriteType.READ) {
|
if (readWriteType == ReadWriteType.READ) {
|
||||||
// 读锁判断最后一个写锁没有了就可以获得锁了
|
// 读锁判断最后一个写锁没有了就可以获得锁了
|
||||||
if (writeList.size() == 0) {
|
if (writeList.size() == 0) {
|
||||||
// 我是读锁,并且没有写锁,直接获得
|
// 我是读锁,并且没有写锁,直接获得
|
||||||
return;
|
// return;
|
||||||
} else {
|
} else {
|
||||||
// 读锁但是有写锁,监听最后一个写锁
|
// 读锁但是有写锁,监听最后一个写锁
|
||||||
String lastPath = writeList.get(writeList.size() - 1);
|
String lastPath = writeList.get(writeList.size() - 1);
|
||||||
@ -126,8 +119,7 @@ public class ZkLock {
|
|||||||
if (writeList.size() == 1) {
|
if (writeList.size() == 1) {
|
||||||
// 获取到锁,已经没人获取到读锁了
|
// 获取到锁,已经没人获取到读锁了
|
||||||
if (readList.size() == 0 || shouldWrite) {
|
if (readList.size() == 0 || shouldWrite) {
|
||||||
|
// return;
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
String first = readList.get(0);
|
String first = readList.get(0);
|
||||||
cirLock(first);
|
cirLock(first);
|
||||||
@ -137,7 +129,7 @@ public class ZkLock {
|
|||||||
if (writeList.lastIndexOf(name) == 0) {
|
if (writeList.lastIndexOf(name) == 0) {
|
||||||
// 获取到锁
|
// 获取到锁
|
||||||
if (readList.size() == 0) {
|
if (readList.size() == 0) {
|
||||||
return;
|
// return;
|
||||||
} else {
|
} else {
|
||||||
String first = readList.get(0);
|
String first = readList.get(0);
|
||||||
cirLock(first);
|
cirLock(first);
|
||||||
@ -149,14 +141,11 @@ public class ZkLock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没有写锁,全部都不阻塞
|
// 没有写锁,全部都不阻塞
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void cirLock(String lastPath) throws Exception {
|
protected void cirLock(String lastPath) throws Exception {
|
||||||
// 获得上一个锁对象
|
// 获得上一个锁对象
|
||||||
|
|
||||||
NodeCache nodeCache = new NodeCache(ZK_CLIENT, getPath() + "/" + lastPath);
|
NodeCache nodeCache = new NodeCache(ZK_CLIENT, getPath() + "/" + lastPath);
|
||||||
|
|
||||||
nodeCache.start();
|
nodeCache.start();
|
@ -1,13 +0,0 @@
|
|||||||
package io.github.ehlxr.zkrwlock;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
public class ZkRwLockApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(ZkRwLockApplication.class, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package io.github.ehlxr.zkrwlock.controller;
|
|
||||||
|
|
||||||
|
|
||||||
import io.github.ehlxr.zkrwlock.lockv2.ZkLock;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public class Controller {
|
|
||||||
|
|
||||||
String lockName = "test";
|
|
||||||
/**
|
|
||||||
* ---------------非公平锁,重制命令每次执行都会优先于读取命令
|
|
||||||
*/
|
|
||||||
@GetMapping("/test03")
|
|
||||||
public void test03() throws InterruptedException {
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
new Thread(()->{
|
|
||||||
ZkLock lock = new ZkLock(lockName, ZkLock.ReadWriteType.READ);
|
|
||||||
|
|
||||||
try {
|
|
||||||
lock.lock();
|
|
||||||
Thread.sleep(1000);
|
|
||||||
System.out.println("读请求,耗时50毫秒");
|
|
||||||
}catch (Exception e){
|
|
||||||
|
|
||||||
}finally {
|
|
||||||
lock.unLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@GetMapping("/test04")
|
|
||||||
public void test04() throws Exception {
|
|
||||||
ZkLock lock = new ZkLock(lockName, ZkLock.ReadWriteType.WRITE);
|
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
System.out.println("写请求");
|
|
||||||
Thread.sleep(2000);
|
|
||||||
lock.unLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/test05")
|
|
||||||
public void test05(){
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.ehlxr.zkrwlock.lock;
|
package io.github.ehlxr.zkrwlock.v1;
|
||||||
|
|
||||||
import org.apache.zookeeper.CreateMode;
|
import org.apache.zookeeper.CreateMode;
|
||||||
import org.apache.zookeeper.ZooDefs;
|
import org.apache.zookeeper.ZooDefs;
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.ehlxr.zkrwlock.lock;
|
package io.github.ehlxr.zkrwlock.v1;
|
||||||
|
|
||||||
import org.apache.zookeeper.*;
|
import org.apache.zookeeper.*;
|
||||||
import org.apache.zookeeper.data.Stat;
|
import org.apache.zookeeper.data.Stat;
|
@ -1,2 +0,0 @@
|
|||||||
server:
|
|
||||||
port: 9080
|
|
45
src/main/resources/logback.xml
Normal file
45
src/main/resources/logback.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%date [%thread] %-5level %logger{35}:%line - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_PATH:-.}/logs/zkrwlock-error.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_PATH:-.}/logs/zkrwlock-error.log.%d{yyyy-MM-dd}</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%date [%thread] %-5level %logger{35}:%line - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="NORMAL" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_PATH:-.}/logs/zkrwlock-server.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_PATH:-.}/logs/zkrwlock-server.log.%d{yyyy-MM-dd}</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%date [%thread] %-5level %logger{35}:%line - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
|
<appender-ref ref="NORMAL"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright © 2020 xrv <xrg@live.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.ehlxr.zkrwlock;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.framework.imps.CuratorFrameworkState;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessLock;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
|
||||||
|
import org.apache.curator.retry.RetryOneTime;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.CyclicBarrier;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ehlxr
|
||||||
|
* @since 2021-02-03 22:42.
|
||||||
|
*/
|
||||||
|
public class InterProcessReadWriteLockTest {
|
||||||
|
private static CuratorFramework ZK_CLIENT;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
ZK_CLIENT = CuratorFrameworkFactory.builder()
|
||||||
|
.connectString("localhost:2181")
|
||||||
|
.sessionTimeoutMs(2000000)
|
||||||
|
.retryPolicy(new RetryOneTime(10000))
|
||||||
|
// 命名空间,用该客户端操作的东西都在该节点之下
|
||||||
|
.namespace("lock")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ZK_CLIENT.start();
|
||||||
|
|
||||||
|
if (ZK_CLIENT.getState() == CuratorFrameworkState.STARTED) {
|
||||||
|
System.out.println("启动成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void reentrantReadLockTest() throws Exception {
|
||||||
|
int num = 2;
|
||||||
|
CountDownLatch latch = new CountDownLatch(num);
|
||||||
|
|
||||||
|
IntStream.range(0, num).forEach(i -> {
|
||||||
|
// 创建共享可重入读锁
|
||||||
|
InterProcessLock readLock = new InterProcessReadWriteLock(ZK_CLIENT, "/test").readLock();
|
||||||
|
|
||||||
|
// 获取锁对象
|
||||||
|
try {
|
||||||
|
readLock.acquire();
|
||||||
|
System.out.println(i + "获取读锁===============");
|
||||||
|
// 测试锁重入
|
||||||
|
readLock.acquire();
|
||||||
|
System.out.println(i + "再次获取读锁===============");
|
||||||
|
Thread.sleep(2000);
|
||||||
|
readLock.release();
|
||||||
|
System.out.println(i + "释放读锁===============");
|
||||||
|
readLock.release();
|
||||||
|
System.out.println(i + "再次释放读锁===============");
|
||||||
|
|
||||||
|
latch.countDown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rwLockTest() throws Exception {
|
||||||
|
/*
|
||||||
|
* 读线程不互斥
|
||||||
|
*/
|
||||||
|
int num = 50;
|
||||||
|
CountDownLatch latch = new CountDownLatch(num);
|
||||||
|
CyclicBarrier barrier = new CyclicBarrier(num);
|
||||||
|
|
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "+ 开始读请求。。。。" 与 "= 读请求结束。。。。" 交叉出现
|
||||||
|
*/
|
||||||
|
pool.execute(() -> IntStream.range(0, num).parallel().forEach(i -> {
|
||||||
|
InterProcessMutex lock = new InterProcessReadWriteLock(ZK_CLIENT, "/test").readLock();
|
||||||
|
try {
|
||||||
|
System.out.println("> 读请求就绪。。。。" + i + " " + Thread.currentThread().getName());
|
||||||
|
barrier.await();
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
System.out.println("+ 开始读请求。。。。" + i + " " + Thread.currentThread().getName());
|
||||||
|
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.out.println("= 读请求结束。。。。" + i + " " + Thread.currentThread().getName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
lock.release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
InterProcessMutex lock = new InterProcessReadWriteLock(ZK_CLIENT, "/test").writeLock();
|
||||||
|
try {
|
||||||
|
lock.acquire();
|
||||||
|
System.out.println("\n开始写请求。。。。");
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.out.println("写请求结束。。。。\n");
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
pool.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wwTest() throws InterruptedException {
|
||||||
|
int num = 5;
|
||||||
|
CountDownLatch latch = new CountDownLatch(num);
|
||||||
|
CyclicBarrier barrier = new CyclicBarrier(num);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "+ 开始写请求。。。。" 与 "= 写请求结束。。。。" 成对出现
|
||||||
|
*/
|
||||||
|
IntStream.range(0, num).parallel().forEach(i -> {
|
||||||
|
InterProcessMutex lock = new InterProcessReadWriteLock(ZK_CLIENT, "/test").writeLock();
|
||||||
|
try {
|
||||||
|
System.out.println("> 写请求就绪。。。。" + i + " " + Thread.currentThread().getName());
|
||||||
|
barrier.await();
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
System.out.println("\n+ 开始写请求。。。。" + i + " " + Thread.currentThread().getName());
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.out.println("= 写请求结束。。。。" + i + " " + Thread.currentThread().getName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
lock.release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
}
|
||||||
|
}
|
112
src/test/java/io/github/ehlxr/zkrwlock/ZkRWLockTest.java
Normal file
112
src/test/java/io/github/ehlxr/zkrwlock/ZkRWLockTest.java
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright © 2020 xrv <xrg@live.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.ehlxr.zkrwlock;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.CyclicBarrier;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ehlxr
|
||||||
|
* @since 2021-02-03 20:54.
|
||||||
|
*/
|
||||||
|
public class ZkRWLockTest {
|
||||||
|
private final String lockName = "test";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rwTest() throws InterruptedException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(2);
|
||||||
|
// ExecutorService pool = Executors.newFixedThreadPool(10);
|
||||||
|
// ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||||
|
|
||||||
|
IntStream.range(0, 100).parallel().forEachOrdered(i -> {
|
||||||
|
// pool.execute(() -> {
|
||||||
|
ZkLock lock = new ZkLock(lockName, ZkLock.ReadWriteType.READ);
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
Thread.sleep(500);
|
||||||
|
System.out.println("读请求" + i);
|
||||||
|
latch.countDown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
lock.unLock();
|
||||||
|
}
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
ZkLock lock = new ZkLock(lockName, ZkLock.ReadWriteType.WRITE);
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
System.out.println("开始写请求。。。。");
|
||||||
|
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.out.println("写请求结束。。。。");
|
||||||
|
lock.unLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
// pool.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wwTest() throws InterruptedException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(2);
|
||||||
|
// ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||||
|
CyclicBarrier barrier = new CyclicBarrier(2);
|
||||||
|
|
||||||
|
IntStream.range(0, 2).parallel().forEach(i -> {
|
||||||
|
// pool.execute(() -> {
|
||||||
|
ZkLock lock = new ZkLock(lockName, ZkLock.ReadWriteType.WRITE);
|
||||||
|
try {
|
||||||
|
System.out.println("写请求就绪。。。。" + i);
|
||||||
|
barrier.await();
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
|
System.out.println("开始写请求。。。。" + i);
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
System.out.println("写请求结束。。。。" + i);
|
||||||
|
latch.countDown();
|
||||||
|
lock.unLock();
|
||||||
|
}
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
// pool.shutdown();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user