在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);
}
}