测试Java的synchronize和ReentrantLock在单线程下的效率

简介:

ReentrantLock 在多线程情况下要远胜synchronize,这点没有疑问。

最近要写个程序,有个变量是有多数情况下是一个线程读写,有少数情况下是多个线程并发读写。所以要测试下ReentrantLock 在单线程下和synchronize的效率对比。

在测试的过程中发现一个有意思的现象。

测试代码见后面。

测试代码1结果:

noLockTime: 0:00:00.004
noLockTime: 0:00:00.006
noLockTime: 0:00:00.000
syncTime: 0:00:02.902
syncTime: 0:00:02.902
syncTime: 0:00:02.886
ReentrantTime: 0:00:05.012
ReentrantTime: 0:00:05.007
ReentrantTime: 0:00:04.270

则开始看到这个测试结果,觉得相当奇怪,ReentrantLock居然比synchronize要慢这么多。

但是后来再仔细研究测试结果,发现原来是jvm把测试代码优化掉了!观察noLockTime的时间,差不多是0!

于是加上total的统计代码,得到以下的测试结果:

加上total统计的测试代码结果:

noLockTime: 0:00:03.786
total:1078760960
noLockTime: 0:00:03.774
total:1078760960
noLockTime: 0:00:03.428
total:1078760960
syncTime: 0:00:05.553
total:1078760960
syncTime: 0:00:05.555
total:1078760960
syncTime: 0:00:04.826
total:1078760960
ReentrantTime: 0:00:05.451
total:1078760960
ReentrantTime: 0:00:05.424
total:1078760960
ReentrantTime: 0:00:04.493
total:1078760960


这个结果算是正常的结果了。


总结:

  1. 以前一直听说JVM可以在运行时优化代码,果然是相当的牛B的功能,直接在运行时把无用的代码全优化掉了。
  2. 测试程序要注意防止jvm等的优化
  3. ReentrantLock和synchronize在单线程下效率基本一样(从实现原理来看,在单线程情况下,都是一个比较指令即可)
  4. 在单线程下,ReentrantLock和synchronize的效率是非常高的,一次调用约10e-11秒。


测试代码1:

import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang3.time.StopWatch;

public class XXX {
	static ReentrantLock lock = new ReentrantLock(false);
	static int size = 100;
	static int count = 100000000;
	
	static StopWatch watch = new StopWatch();
	public static void main(String[] args) {
		noLockTime();
		noLockTime();
		noLockTime();
		
		syncTime();
		syncTime();
		syncTime();
		
		ReentrantTime();
		ReentrantTime();
		ReentrantTime();
	}
	
	static void noLockTime(){
//		int total = 0;
		watch.reset();
		watch.start();
		for(int i = 0; i < count; ++i){
			testNotLock();
//			total += testNotLock();
		}
		watch.stop();
		System.out.println("noLockTime: " + watch);
//		System.out.println("total:" + total);
	}
	
	static void syncTime(){
//		int total = 0;
		watch.reset();
		watch.start();
		for(int i = 0; i < count; ++i){
			testSync();
//			total += testSync();
		}
		watch.stop();
		System.out.println("syncTime: " + watch);
//		System.out.println("total:" + total);
	}
	
	static void ReentrantTime(){
//		int total = 0;
		watch.reset();
		watch.start();
		for(int i = 0; i < count; ++i){
			testReentrantLock();
//			total += testReentrantLock();
		}
		watch.stop();
		System.out.println("ReentrantTime: " + watch);
//		System.out.println("total:" + total);
	}
	
	static int testNotLock(){
		int sum = 0;
		for(int i = 0; i < size; ++i){
			sum += i;
		}
		return sum;
	}
	
	static synchronized int testSync(){
		int sum = 0;
		for(int i = 0; i < size; ++i){
			sum += i;
		}
		return sum;
	}
	
	static int testReentrantLock(){
		try{
			lock.lock();
			int sum = 0;
			for(int i = 0; i < size; ++i){
				sum += i;
			}
			return sum;
		}finally{
			lock.unlock();
		}
	}
	
}



加上total统计的测试代码:

import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang3.time.StopWatch;

public class XXX {
	static ReentrantLock lock = new ReentrantLock(false);
	static int size = 100;
	static int count = 100000000;
	
	static StopWatch watch = new StopWatch();
	public static void main(String[] args) {
		noLockTime();
		noLockTime();
		noLockTime();
		
		syncTime();
		syncTime();
		syncTime();
		
		ReentrantTime();
		ReentrantTime();
		ReentrantTime();
	}
	
	static void noLockTime(){
		int total = 0;
		watch.reset();
		watch.start();
		for(int i = 0; i < count; ++i){
//			testNotLock();
			total += testNotLock();
		}
		watch.stop();
		System.out.println("noLockTime: " + watch);
		System.out.println("total:" + total);
	}
	
	static void syncTime(){
		int total = 0;
		watch.reset();
		watch.start();
		for(int i = 0; i < count; ++i){
//			testSync();
			total += testSync();
		}
		watch.stop();
		System.out.println("syncTime: " + watch);
		System.out.println("total:" + total);
	}
	
	static void ReentrantTime(){
		int total = 0;
		watch.reset();
		watch.start();
		for(int i = 0; i < count; ++i){
//			testReentrantLock();
			total += testReentrantLock();
		}
		watch.stop();
		System.out.println("ReentrantTime: " + watch);
		System.out.println("total:" + total);
	}
	
	static int testNotLock(){
		int sum = 0;
		for(int i = 0; i < size; ++i){
			sum += i;
		}
		return sum;
	}
	
	static synchronized int testSync(){
		int sum = 0;
		for(int i = 0; i < size; ++i){
			sum += i;
		}
		return sum;
	}
	
	static int testReentrantLock(){
		try{
			lock.lock();
			int sum = 0;
			for(int i = 0; i < size; ++i){
				sum += i;
			}
			return sum;
		}finally{
			lock.unlock();
		}
	}
	
}


目录
相关文章
|
1月前
|
安全 Java
java保证线程安全关于锁处理的理解
了解Java中确保线程安全的锁机制:1)全局synchronized方法实现单例模式;2)对Vector/Collections.SynchronizedList/CopyOnWriteArrayList的部分操作加锁;3)ConcurrentHashMap的锁分段技术;4)使用读写锁;5)无锁或低冲突策略,如Disruptor队列。
20 2
|
24天前
|
安全 算法 Java
Java中的多线程并发控制与同步机制
【4月更文挑战第17天】 在现代软件开发中,Java作为一种广泛使用的编程语言,其对多线程的支持是构建高性能应用程序的关键。本文将深入探讨Java中的多线程并发控制与同步机制,包括基本的线程创建、生命周期管理,以及高级的并发工具如synchronized关键字、ReentrantLock类、并发集合和原子变量等。通过理论分析与实例演示,旨在为读者提供一个清晰的多线程并发控制与同步的实现框架,并指出在实践中如何避免常见的并发问题,如死锁、竞态条件和资源争用等。
|
27天前
|
Java 程序员 编译器
Java中的线程同步与锁优化策略
【4月更文挑战第14天】在多线程编程中,线程同步是确保数据一致性和程序正确性的关键。Java提供了多种机制来实现线程同步,其中最常用的是synchronized关键字和Lock接口。本文将深入探讨Java中的线程同步问题,并分析如何通过锁优化策略提高程序性能。我们将首先介绍线程同步的基本概念,然后详细讨论synchronized和Lock的使用及优缺点,最后探讨一些锁优化技巧,如锁粗化、锁消除和读写锁等。
|
1月前
|
Java
Java中的多线程并发控制与锁机制
【4月更文挑战第11天】本文将深入探讨Java中的多线程并发控制与锁机制。我们将首先介绍多线程的基本概念,然后详细解析Java中的锁机制,包括synchronized关键字和Lock接口。最后,我们将通过实例代码,展示如何在Java中实现多线程并发控制。
|
5月前
|
Java
多线程与并发,Java中如何避免死锁?
多线程与并发,Java中如何避免死锁?
67 5
|
7月前
|
Java 程序员 调度
JUC第三讲:Java 并发-线程基础
JUC第三讲:Java 并发-线程基础
|
7月前
|
缓存 算法 安全
JUC第四讲:Java中的锁/CAS原理与案例分析(下)
JUC第四讲:Java中的锁/CAS原理与案例分析
|
7月前
|
缓存 安全 算法
JUC第四讲:Java中的锁/CAS原理与案例分析(上)
JUC第四讲:Java中的锁/CAS原理与案例分析
JUC第四讲:Java中的锁/CAS原理与案例分析(上)
|
9月前
|
安全 Java 调度
【Java|多线程与高并发】线程安全问题以及synchronized使用实例
Java多线程环境下,多个线程同时访问共享资源时可能出现的数据竞争和不一致的情况。
|
12月前
|
Java
Java:从单线程计数器到多线程数据同步synchronized和原子类Atomic
Java:从单线程计数器到多线程数据同步synchronized和原子类Atomic
121 0