Padded优化LinkedTransferQue并发性能是错误方向

孤街醉人 提交于 2020-03-01 08:44:15

在Grizzly中,自带了LinkedTransferQueue,和JDK 7自带的LinkedTransferQueue有所不同,不同之处就是使用PaddedAtomicReference来提升并发性能,其实这是一种错误的编码技巧,没有意义!

AtomicReference和LinkedTransferQueue的本质是乐观锁,乐观锁的在激烈竞争的时候性能都很糟糕,乐观锁应使用在非激烈竞争的场景,为乐观锁优化激烈竞争下的性能,是错误的方向,因为如果需要激烈竞争,就应该使用悲观锁。

以下是一个JDK中内置乐观锁悲观锁的对照表:

乐观锁           ----->  悲观锁

AtomicInteger   ----->  Lock + volatile int

AtomicLong      ----->  Lock + volatile long

AtomicReference ----->  Lock + volatile

LinkedTransferQueue -----> LinkedBlockingQueue

在激烈竞争中,LinkedTransferQueue的性能,远远低于LinkedBlockingQueue,使用PaddedAtomicReference优化也是一样的。如果不激烈竞争,Padded-LinkedTransferQueue和LinkedTransferQueue相比也没有什么优势。

所以Padded-AtomicReference也是一个伪命题,如果激励竞争,为什么不使用Lock + volatile,如果非激烈竞争,使用PaddedAtomicReference对于AtomicReference又没有优势。所以使用Padded-AtomicReference是一个错误的编码技巧。

以下是测试代码,50个线程争用10个对象,这种激烈竞争下,使用LinkedTransferQueue比LinkedBlockingQueue大约慢10倍。

package com.alibaba.study;

import java.util.concurrent.*;

public class BlockingQueueTest {
	public static void main(String[] args) throws Exception {
		for (int i = 0; i < 3; ++i) {
			loop();
		}		
	}
	
	private static void loop() throws InterruptedException {
		final BlockingQueue<Object> queue = new LinkedBlockingQueue<Object>();
//		final BlockingQueue<Object> queue = new LinkedTransferQueue<Object>();

		for (int i = 0; i < 10; ++i) {
			queue.put(i);
		}

		final int THREAD_COUNT = 50;
		final CountDownLatch startLatch = new CountDownLatch(1);
		final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT);

		for (int i = 0; i < THREAD_COUNT; ++i) {
			Thread thread = new Thread() {
				public void run() {
					try {
						startLatch.await();
					} catch (InterruptedException e) { e.printStackTrace(); }

					try {
						for (int i = 0; i < 1000 * 20; ++i) {
							Object item = queue.take();
							queue.put(item);
						}
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						endLatch.countDown();
					}
				}
			};
			thread.start();
		}

		long startMillis = System.currentTimeMillis();
		startLatch.countDown();
		endLatch.await();
		long millis = System.currentTimeMillis() - startMillis;
		System.out.println(queue.getClass().getName() + " : " + millis);
	}
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!