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

简介: ReentrantLock 在多线程情况下要远胜synchronize,这点没有疑问。最近要写个程序,有个变量是有多数情况下是一个线程读写,有少数情况下是多个线程并发读写。

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();
		}
	}
	
}


相关文章
|
10月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
441 1
|
10月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
411 1
|
11月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
460 0
|
11月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
633 16
|
12月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
1011 0
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
407 0
|
人工智能 Java 测试技术
Java or Python?测试开发工程师如何选择合适的编程语言?
测试工程师如何选择编程语言?Java 还是 Python?多位资深专家分享建议:Python 入门简单、开发效率高,适合新手及自动化测试;Java 生态成熟,适合大型项目和平台开发。建议结合公司技术栈、个人基础及发展方向选择。长远来看,两者兼通更佳,同时关注 Go 等新兴语言。快速学习与实践才是关键。