synchronizedとLockの2種類のロックの性能テストと比較

25598 ワード

この2つのロックについてjdk 1である.6以前のsynchronizedの性能はロックに及ばなかった.synchronizedはオペレーティングシステムの関数を呼び出す必要があるため、オペレーティングカーネルが完成し、JDK 1で比較的時間がかかる.6以降、Oracle社はsynchronizedを大量に最適化し、偏向ロック、スピンロックなどのjvmレベルのロックメカニズムを導入し、性能を大幅に向上させ、JDK 1が一般的に使用されている.8の今、好奇心から、私は簡単にsynchronizedとLockをJDK 1でテストしました.2つの間のパフォーマンスを8回実行します.
単一スレッドでsynchronizedとLockを使用してそれぞれ100回0~100万の重ね合わせ操作を行います.この場合、ロック解除を100回繰り返します.テストコードは以下の通りです.
public class Test2 {
	private static Lock lock = new ReentrantLock();
	public static void main(String[] args) throws InterruptedException {
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100; i++) {
			function1();
		}
		System.out.println("   ,synchronized  :" + (System.currentTimeMillis() - start));

		/*long start2 = System.currentTimeMillis();
		for (int i = 0; i < 100; i++) {
			function2();
		}
		System.out.println("   ,Lock  :" + (System.currentTimeMillis() - start2));*/
	}

	/**
	 *   synchronized  1-100    
	 */
	public synchronized static void function1() {
			int sum = 0;
			for (int i = 0; i < 1000000; i++) {
				sum += i;
			}
	}
	
	/**
	 *   Lock  1-100    
	 */
	public static void function2() {
		lock.lock();
		int sum = 0;
		for (int i = 0; i < 1000000; i++) {
			sum += i;
		}
		lock.unlock();
	}
}

結果(各3回の結果を取る):
synchronized  :6synchronized  :5synchronized  :5

   ,Lock  :35
   ,Lock  :35
   ,Lock  :35

単一スレッドの場合、synchronizedの性能はLockより優れ、synchronizedのロック解除ロック速度はLockより速いことがわかる.
10スレッドでsynchronizedとlockをそれぞれ100回使用して0~100万のオーバーラップ操作を行い、10回ロックを競合します.テストコードは以下の通りです.
	/*----------------------------------------------------*/
	/*--------------------     -------------------------*/
	/*----------------------------------------------------*/
public class Test {
	//    
	private static int threadCounts = 10;
	//         ,        
	public static CountDownLatch latch = new CountDownLatch(threadCounts);
	//            
	public static CyclicBarrier cyc = new CyclicBarrier(threadCounts + 1);

	public static void main(String[] args) {
		List<Thread> threads1 = new ArrayList<>();
		for (int i = 0; i < threadCounts; i++) {
			Thread thread = new Thread(new SyncTest());
			threads1.add(thread);
			thread.start();
			latch.countDown();
		}
		long start = System.currentTimeMillis();
		try {
			Test.cyc.await();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(threadCounts+"   ,synchronized  :"+(System.currentTimeMillis()-start));
		/*---------------------   lock,    ,       --------------------------*/
		/*Lock lock = new ReentrantLock();
		List threads = new ArrayList<>();
		for (int i = 0; i < threadCounts; i++) {
			Thread thread = new Thread(new LockTest(lock));
			threads.add(thread);
			thread.start();
			latch.countDown();
		}
		long start2 = System.currentTimeMillis();
		try {
			Test.cyc.await();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(threadCounts + "   ,lock  :" + (System.currentTimeMillis() - start2));*/
	}
}

/**
 * synchronized Runnable 
 */
class SyncTest implements Runnable {

	@Override
	public void run(){
		try {
			Test.latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		synchronized (SyncTest.class) {
			for (int i = 0; i < 100; i++) {
				function();
			}
			Test.i++;
		}
		try {
			Test.cyc.await();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void function() {
		int sum = 0;
		for (int i = 0; i < 1000000; i++) {
			sum += i;
		}
	}
}

/**
 * Lock Runnable 
 */
class LockTest implements Runnable {

	private Lock lock;

	public LockTest(Lock lock) {
		this.lock = lock;
	}

	@Override
	public void run() {
		try {
			Test.latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		lock.lock();
		for (int i = 0; i < 100; i++) {
			function();
		}
		lock.unlock();
		try {
			Test.cyc.await();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void function() {
		int sum = 0;
		for (int i = 0; i < 1000000; i++) {
			sum += i;
		}
	}
}


結果(各3回の結果を取る):
10synchronized5
10synchronized5
10synchronized5

10   ,lock  :5
10   ,lock  :5
10   ,lock  :5

上記と同じコードロジックで、スレッド数を1000に調整し、以下の結果を得た(各3回の結果を取る):
1000synchronized72
1000synchronized60
1000synchronized67

1000   ,lock  :82
1000   ,lock  :85
1000   ,lock  :83

最後に,スレッド数を1万に調整し,以下の結果を得た(各3回の結果をとる).
10000synchronized6613
10000synchronized7619
10000synchronized7063

10000   ,lock  :7310
10000   ,lock  :7257
10000   ,lock  :7905

今回のテストは簡単ですが、jdk 1も基本的に見ることができます.8バージョンでは、synchronizedとLockのパフォーマンスは1万個以内であまり変わらないが、これらのテストデータは私がノートパソコンを使ってテストしたもので、簡単な参考になるだけだ.