在配置文件中设置使用哪个锁,使用junit测试
static int total = 20;//开启循环数
@Test
@Rollback(false)
public void contextLoads() throws Exception {
Date startTime = new Date();
Long waitTime = 1000L;//线程执行时间
CountDownLatch totalLatch = new CountDownLatch(total);
for(int i=0;i<total;i++) {
testLock("lock"+i+"lock", 30, startTime, waitTime, totalLatch);
}
totalLatch.await();
}
//记录所有程序执行的线程数量
static List<Number> totalNumber = Collections.synchronizedList(new ArrayList<Number>());
/**
* 测试锁的效率
* @param lockName 锁的名称
* @param cycle 开启线程数
* @param start 总开始时间
* @param waitTime 线程执行时间
* @param totalLatch 总计数器归零后结束总线程
*/
private static void testLock(String lockName, int cycle, Date start, Long waitTime, CountDownLatch totalLatch) {
Number num = new Number();
totalNumber.add(num);
Date begin = new Date();
CountDownLatch latch = new CountDownLatch(cycle);
new Thread(new Runnable() {//开启一个线程,直到所有的线程结束后打印执行日志
@Override
public void run() {
try {
latch.await();
System.out.println("花费时间:"+(new Date().getTime() - begin.getTime()));
System.out.println("总执行时间:"+(new Date().getTime() - start.getTime()));
System.out.println("总循环数:"+total);
System.out.println("执行个数:"+num);
System.out.println(totalNumber);
totalLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for(int i = 0;i<cycle;i++) {//开启cycle个线程执行锁
Runnable runnable = new Runnable() {
public void run() {
try {
BaseLockProxy.commonZookeeperLock(lockName, new BaseLockCallBack() {
@Override
public void run() throws Exception {
Thread.sleep(waitTime);
num.addNum();
System.out.println(num);
System.out.println(totalNumber);
System.out.println("Thread " + Thread.currentThread().getId() + "正在运行");
}
});
} catch (Exception e1) {
e1.printStackTrace();
}
latch.countDown();
}
};
Thread t = new Thread(runnable);
t.start();
}
}
public class Number{
private int num = 0;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public void addNum() throws InterruptedException {
this.num = num + 1;
}
@Override
public String toString() {
return "" + num;
}
}
Number计数可以用来分析锁是否有效,如果锁无效或者不可靠,那么num数量就会小于cycle的值
下面是实验的结果,都只执行了一次。
总循环数10,一个循环开启线程数10,执行时间1000ms
zookeeper
花费时间:10948
总执行时间:11023
总循环数:10
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
Redisson
花费时间:10252
总执行时间:10252
总循环数:10
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
总循环数10,一个循环开启线程数10,执行时间3000ms
zookeeper
花费时间:30986
总执行时间:30990
总循环数:10
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
Redisson
花费时间:30132
总执行时间:30135
总循环数:10
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
总循环数20,一个循环开启线程数30,执行时间1000ms
zookeeper
花费时间:41124
总执行时间:41345
总循环数:20
执行个数:30
[30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]
Redisson
花费时间:31677
总执行时间:31719
总循环数:20
执行个数:30
[30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]
总循环数20,一个循环开启线程数30,执行时间3000ms
zookeeper
花费时间:121700
总执行时间:122298
总循环数:20
执行个数:30
[30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]
redisson
花费时间:91745
总执行时间:91801
总循环数:20
执行个数:30
[30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]
总循环数50,一个循环开启线程数10,执行时间1000ms
zookeeper
花费时间:19271
总执行时间:19561
总循环数:50
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
redisson
花费时间:11754
总执行时间:11803
总循环数:50
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
总循环数50,一个循环开启线程数10,执行时间3000ms
Zookeeper
花费时间:50475
总执行时间:50509
总循环数:50
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
redisson
花费时间:31754
总执行时间:31808
总循环数:50
执行个数:10
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
总循环数 | 开启线程数 | 执行时间(ms) | 锁类型 | 总耗时(ms) |
10
| 10
| 1000
| zookeeper | 11023 |
Redisson | 10252 | |||
3000
| Zookeeper | 30990 | ||
Redisson | 30135 | |||
20
| 30
| 1000
| zookeeper | 41345 |
Redisson | 31719 | |||
3000
| Zookeeper | 122298 | ||
Redisson | 91801 | |||
50
| 10
| 1000
| zookeeper | 19561 |
Redisson | 11803 | |||
3000
| Zookeeper | 50509 | ||
Redisson | 31808 |
实验结果,redisson的性能全面优于zookeeper,在并发数少的时候不明显,当争抢一个锁的线程明显增加,或者同时存在的锁的数量增加,或者程序的执行时间增加,都会明显地增加zookeeper锁花费的额外时间,
并且按影响来说
同时存在的锁数量>一个锁下面执行的线程数量>程序的执行时间
并且在测试zookeeper锁的过程中会出现一个锁释放了,但是没有及时监听到释放事件,导致等到超时时间30s后检测到锁已经释放才拿到锁,遇到这种情况我只好重新测试一遍,所以测试结果中已经是去掉了这种偶发的特殊情况,不然zookeeper锁消耗的时间会更多。
而redisson锁在各种情况下其消耗的时间都接近 开启线程数×执行时间,也就是说锁消耗的时间几乎可以忽略不计。
而从内存上来说,目测发现测试zookeeper锁时eclipse的内存一直在波动900M~1300M之间,而测试redisson锁,内存一直稳定在1200M,zookeeper锁可能对内存进行了更多的增删操作,而redisson锁占用了更多的内存但是比较稳定。这只是推理,具体对资源的消耗还要看实际执行情况。
总结:redisson锁的效率和可靠性要大于zookeeper锁(自己实现),而且zookeeper锁还有编号数字大了以后新增的节点编号会小于之前的节点编号的致命bug,需要定时重建
因为我们是把redisson锁放在通用类里面的,所以每个项目都会注入redissonClient,然后发现测试服务器占用了很多内存,仅仅只是启动还没有运行。
然后我发现只要注入了RedissonClient,在用junit执行测试代码的最后都会报一堆这个错误,不管是否使用了redisson锁。
我猜测redissonClient启动时会建立一个线程池,然后使用时会从线程池里取一些连接,因此只要启动了就会耗费一定的内存。
之后得了解一下原理了,看看能不能通过设置减少内存消耗
运维说在tomcat9.0里面会出占内存的问题,但是在tomcat8.5就没关系。。。摸不着头脑