閱讀610 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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


最後更新:2017-04-02 16:47:37

  上一篇:go .NET中安裝SVN
  下一篇:go android 雙擊圖片放大縮小