重要说明:以下内容和观点基于本人PC的测试结果,数据量不大,并且分析也不够深入。仅供学习参考。
最近写了个例子,比较了一下synchronized和ReentrantLock的性能,分享一下数据和个人观点。
例子
public class SycTest {
private Object ob = new Object();
static synchronized void abc(String x){
print(x);
}
synchronized void cde(String y){
print(y);
}
synchronized void def(String y){
print(y);
}
void fgh(String z){
synchronized (ob){
print(z);
}
}
static void print(String c){
for(int i=0;i<4 ;i++){
System.out.print(c+",");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
SycTest test = new SycTest();
Thread t1 = new Thread(()->{test.cde("t1");});
Thread t2 = new Thread(()->{test.def("t2");});
Thread t3 = new Thread(()->{abc("t3");});
Thread t4 = new Thread(()->{test.cde("t4");});
Thread t5 = new Thread(()->{test.fgh("t5");});
List<Thread> threads = new ArrayList<>(5);
threads.add(t1);
threads.add(t2);
threads.add(t3);
threads.add(t4);
threads.add(t5);
threads.parallelStream().forEach(t->t.start());
}
}
本例中有位移运算和写文件操作。本人PC处理器是4核,java version "1.8.0_231",例子中创建20个线程,每次测试循环500遍。
其实我也想测试更多的,但是一是慢,二是再多的数据会让Excel更卡。我做了N次测试,取了几次的数据,做成简易图表。
图中Y轴单位是纳秒,同时我删掉了部分数值特别大的,否则全挤到一块了。
首先是位移运算
第一次synchronized耗时3097800ns
![](https://img.haomeiwen.com/i20957831/eb453464a3d54d47.png)
第一次ReentrantLock耗时10469300ns
![](https://img.haomeiwen.com/i20957831/baf5b1f903c0abd4.png)
第二次synchronized耗时1902600ns
![](https://img.haomeiwen.com/i20957831/4597f324dc606547.png)
第二次ReentrantLock耗时8310800ns
![](https://img.haomeiwen.com/i20957831/bb3fba0da0371dda.png)
小结
synchronized有更好的稳定性和性能,更多点集中在底部,普遍低于500ns,数值高的点比Lock少很多。
然后是写文件
第一次synchronized耗时97618604400ns
![](https://img.haomeiwen.com/i20957831/127f5b513ce4d77d.png)
第一次ReentrantLock耗时87893170600ns
![](https://img.haomeiwen.com/i20957831/9104445085cf82db.png)
第二次synchronized耗时97205823500ns
![](https://img.haomeiwen.com/i20957831/24e08023f88f0348.png)
第二次ReentrantLock耗时89710725000ns
![](https://img.haomeiwen.com/i20957831/d3e08197ee41d554.png)
小结
ReentrantLock性能相对稳定且更好,但是synchronized的点有很多点集中在底部,而ReentrantLock分散的均匀。
底部数据的比较
取第一次位运算的底部放大
synchronized
![](https://img.haomeiwen.com/i20957831/70eee9967a8c4bb5.png)
ReentrantLock
![](https://img.haomeiwen.com/i20957831/65a06b95a727f0d7.png)
能看刚开始普遍耗时多,猜测是1.大量线程启动,2.在获得锁之前需要做运算,CPU繁忙,3竞争激烈。但是在这之后由synchronized做同步的操作都能在100~300之间完成。
我的总结
众所周知,synchronized由于偏向锁等优化性能有明显提高,所以现在单纯的说synchronized性能一定差就不一定准确了。
经过这几天我的反复测试,个人觉得synchronized在轻量化的操作,比如简单运算,变量递增/减,赋值等情况有更好的性能。ReentrantLock更适用于复杂度相对高的操作,比如循环遍历,插入,IO等。
在低并发,特别同时是轻量化的操作,synchronized可能可以获得更好的性能。现实情况中虽然我们可能有几百个线程,但是大多数情况下,对于共享资源的修改,同时只有几个或者十几个,那么使用synchronized也不失为一种好选择。
带来了更多的问题
例子中文件操作受IO干扰比较大,不合理,改成遍历长度100的数组并赋值会怎么样?(经简单测试,lock更快)
在线程重入的情况下两者性能如何呢?(位运算,遍历数组并赋值synchronized更快,高近3个数量级)
组合synchronized和volatile对变量的增减操作和直接使用Atomicxxxx哪个更快(本人PC上是前者快,特别是并发很小的时候)
这里不得再次提一下以上结果都是基于本人PC的测试数据。因为还有10核一台云主机,测试中发现对于本例中文件操作结果是不确定的,对于synchronized+volatile的例子是低并发比如5个线程,那是前者快,否则是后这快。
后记
测试中的数据还可以继续挖掘,比如在某一区间内的分布等。
网友评论