Padded優化LinkedTransferQue併發性能是錯誤方向

在Grizzly中,自帶了LinkedTransferQueue,和JDK 7自帶的LinkedTransferQueue有所不一樣,不一樣之處就是使用PaddedAtomicReference來提高併發性能,其實這是一種錯誤的編碼技巧,沒有意義! java

AtomicReference和LinkedTransferQueue的本質是樂觀鎖,樂觀鎖的在激烈競爭的時候性能都很糟糕,樂觀鎖應使用在非激烈競爭的場景,爲樂觀鎖優化激烈競爭下的性能,是錯誤的方向,由於若是須要激烈競爭,就應該使用悲觀鎖。 併發

如下是一個JDK中內置樂觀鎖悲觀鎖的對照表: oop

樂觀鎖           ----->  悲觀鎖 性能

AtomicInteger   ----->  Lock + volatile int 測試

AtomicLong      ----->  Lock + volatile long 優化

AtomicReference ----->  Lock + volatile 編碼

LinkedTransferQueue -----> LinkedBlockingQueue spa

在激烈競爭中,LinkedTransferQueue的性能,遠遠低於LinkedBlockingQueue,使用PaddedAtomicReference優化也是同樣的。若是不激烈競爭,Padded-LinkedTransferQueue和LinkedTransferQueue相比也沒有什麼優點。 線程

因此Padded-AtomicReference也是一個僞命題,若是激勵競爭,爲何不使用Lock + volatile,若是非激烈競爭,使用PaddedAtomicReference對於AtomicReference又沒有優點。因此使用Padded-AtomicReference是一個錯誤的編碼技巧。 code

如下是測試代碼,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);
	}
}
相關文章
相關標籤/搜索