一次对于synchronized和Lock两种锁的性能测试和比较

  • Post author:
  • Post category:其他


对于这两种锁,在jdk1.6之前synchronized的性能是远不如Lock的,因为synchronized需要调用操作系统的函数,操作内核来完成,比较费时,在JDK1.6以后Oracle公司对synchronized进行了大量优化,引入了偏向锁,自旋锁等jvm级别的锁机制,从而让性能得到了大大的跃升,在普遍使用JDK1.8的现在,出于好奇,我简单测试了下synchronized和Lock在JDK1.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耗时:6
单线程,synchronized耗时:5
单线程,synchronized耗时: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<Thread> 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次结果):

10个线程,synchronized耗时:5
10个线程,synchronized耗时:5
10个线程,synchronized耗时:5

10个线程,lock耗时:5
10个线程,lock耗时:5
10个线程,lock耗时:5

和上面同样的代码逻辑,我将线程数调到1000,得到如下结果(各取3次结果):

1000个线程,synchronized耗时:72
1000个线程,synchronized耗时:60
1000个线程,synchronized耗时:67

1000个线程,lock耗时:82
1000个线程,lock耗时:85
1000个线程,lock耗时:83

最后,我将线程数量调整到1万,得到如下结果(各取3次结果):

10000个线程,synchronized耗时:6613
10000个线程,synchronized耗时:7619
10000个线程,synchronized耗时:7063

10000个线程,lock耗时:7310
10000个线程,lock耗时:7257
10000个线程,lock耗时:7905

这次测试比较简单,但也基本能看出jdk1.8版本中,1万个并发以内synchronized和Lock的性能并没有太大的区别,这些测试数据仅仅是我使用个人笔记本测试所得,仅能当一个简单参考。



版权声明:本文为weixin_41644977原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。