原创

高并发下比较(使用synchronized关键字对UserID阻塞)和(单线程多池对UserID取模)性能

前提:

只测试请求进入队列的耗时,不考虑请求的具体执行时间

结果:

用户锁执行10000000请求耗时:2295
取模执行10000000请求耗时:7650

用户锁执行10000000请求耗时:3474
取模执行10000000请求耗时:7916

用户锁执行3000000请求耗时:1120
取模执行3000000请求耗时:1236

用户锁执行5000000请求耗时:2620
取模执行5000000请求耗时:3883

用户锁执行1000000请求耗时:599
取模执行1000000请求耗时:356

结论:

结论有点出乎想象,本以为无锁条件下性能会更高,但是如下

请求在300w左右两种方式差不多,300w以下取模比较有优势,大于300w使用用户锁性能更高

但是,如果我们的消息分发操作是在io线程,那么使用锁是不好的,极端情况下会阻塞io线程导致无法编解码,再者,1000w请求才是秒级差别,所以,还是使用多线程取模是通用且稳定的方案

测试代码:

LockCompare.java

package lockcompare;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
* 比较高并发条件下,比较用户锁和取模谁的性能高
*
* @Description:
* @author: sniper(1084038709@qq.com)
* @date:2019年8月21日 下午4:27:41
*/
public class LockCompare {

// 锁住userID的线程池
private static ThreadPoolExecutor workPool = new ThreadPoolExecutor(20, 20, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1024 * 4 * 20), new NamedThreadFactory("work1"));
// 并发条件下对userID取模的线程池
private static List<ThreadPoolExecutor> workPoolList2 = new ArrayList<ThreadPoolExecutor>();
// userLock
private static Map<Integer, Object> userLock = new ConcurrentHashMap<Integer, Object>(10000);

static {
for (int j = 0; j < 20; j++) {
ThreadPoolExecutor workPol = new ThreadPoolExecutor(1, 1, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1024 * 4), new NamedThreadFactory("work2" + j));
workPoolList2.add(workPol);
}
}

public static void main(String[] args) {
int reqNum = 10000000;
long c = System.currentTimeMillis();
LockCompare.testDelivery(reqNum);
long d = System.currentTimeMillis();

long a = System.currentTimeMillis();
LockCompare.testSychonzied(reqNum);
long b = System.currentTimeMillis();


System.out.println("用户锁执行" + reqNum + "请求耗时:" + (b - a));
System.out.println("取模执行" + reqNum + "请求耗时:" + (d - c));



}

public static Object getUserLock(int userID) {
Object lock = userLock.get(userID);
if (lock != null) {
return lock;
}
lock = new Object();
userLock.put(userID, lock);
return lock;
}

/**
* 使用关键字
*/
public static void testSychonzied(int reqNum) {
for (int i = 0; i < reqNum; i++) {
// 两种方案userID要一样才能更好比较
int userID = i % 10000;
Object lock = LockCompare.getUserLock(userID);
synchronized (lock) {
try {
workPool.execute(new Task(1));
} catch (Exception e) {
// System.out.println("使用关键字队列满了");
// e.printStackTrace();
}
}
}
}

/**
* 取模
*/
public static void testDelivery(int reqNum) {
for (int i = 0; i < reqNum; i++) {
// 两种方案userID要一样才能更好比较
int userID = i % 10000;
int mod = userID % workPoolList2.size();
try {
workPoolList2.get(mod).execute(new Task(2));
} catch (Exception e) {
// System.out.println("取模");
// e.printStackTrace();
}
}
}

}

class Task implements Runnable {
private int type;

public Task(int type) {
this.type = type;
}

@Override
public void run() {
// do something
//for (int i = 0; i < 100; i++) {
// Math.random();
//}


}

}



正文到此结束
本文目录