synchronized & ReentrantLock 的一点疑问

经过JDK1.6对synchronized的进一步优化,通常情况下,synchronized与lock & unlock 效率差别不大,如果大家做一下简单实验应该不容易得出,见[url=http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html]http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html[/url]中的实验,但在做下面这个实验时,发现两者效率上还是有些区别的。

这是一个最简单的阻塞队列的实现,分别采用synchronized和ReentrantLock来实现,代码如下:

public interface Queue<E> {
public void put(E e);
public E take() throws InterruptedException;
}


import java.util.LinkedList;

public class RawSyncQueue<E> implements Queue<E> {

private LinkedList<E> queue = new LinkedList<E>();

public synchronized void put(E e) {

if (queue.size() == 0) {
notifyAll();
}
queue.add(e);
}

public synchronized E take() throws InterruptedException {

for (;;) {
if (queue.size() == 0) {
wait();
}
if (queue.size() != 0) {
return queue.remove(0);
}
}
}

}



import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockSyncQueue<E> implements Queue<E> {

private Lock lock = new ReentrantLock();
private Condition notEmpty = lock.newCondition();
private LinkedList<E> queue = new LinkedList<E>();

public void put(E e) {
lock.lock();
if (queue.size() == 0) {
notEmpty.signalAll();
}
queue.add(e);
lock.unlock();
}

public E take() throws InterruptedException {

lock.lock();
for (;;) {
if (queue.size() == 0) {
notEmpty.await();
}
if (queue.size() != 0) {
E result = queue.remove(0);
lock.unlock();
return result;
}
}
}

}


采用下面的方式来进行测试:

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class PuterTakerTest {

private static final ExecutorService pool = Executors.newCachedThreadPool();
private final AtomicInteger putSum = new AtomicInteger(0);
private final AtomicInteger takeSum = new AtomicInteger(0);
private final CyclicBarrier barrier;
private final Queue<Integer> bq;
private final int nTrials, nPairs;

public static void testAll(int nParis, int tpt) throws Exception {
System.out.println(nParis + ", " + tpt);
System.out.print("RawSyncQueue: ");
Queue<Integer> rawSyncQueue = new RawSyncQueue<Integer>();
new PuterTakerTest(rawSyncQueue, nParis, tpt).test();
System.out.print("LockSyncQueue: ");
Queue<Integer> lockSyncQueue = new LockSyncQueue<Integer>();
new PuterTakerTest(lockSyncQueue, nParis, tpt).test();
}

public static void testAll(int... params) throws Exception {
if (params.length != 2) {
throw new IllegalArgumentException();
}
testAll(params[0], params[1]);
}

public static void main(String[] args) throws Exception {

int[] params = new int[0];

params = new int[] { 1, 100000 };
testAll(params);
params = new int[] { 2, 100000 };
testAll(params);
params = new int[] { 4, 100000 };
testAll(params);
params = new int[] { 8, 100000 };
testAll(params);
params = new int[] { 16, 100000 };
testAll(params);
params = new int[] { 32, 100000 };
testAll(params);

params = new int[] { 1, 1000000 };
testAll(params);
params = new int[] { 2, 1000000 };
testAll(params);
params = new int[] { 4, 1000000 };
testAll(params);
params = new int[] { 8, 1000000 };
testAll(params);
params = new int[] { 16, 1000000 };
testAll(params);
params = new int[] { 32, 1000000 };
testAll(params);

pool.shutdown();
}

PuterTakerTest(Queue<Integer> queue, int nPairs, int nTrials) throws Exception{
this.bq = queue;
this.nTrials = nTrials;
this.nPairs = nPairs;
this.barrier = new CyclicBarrier(nPairs * 2 + 1);
}

public void test() {
try {

for (int i = 0; i < nPairs; ++i) {
pool.execute(new Producer());
pool.execute(new Consumer());
}
long startTime = System.nanoTime();
barrier.await();
barrier.await();
long nsPerItem = (System.nanoTime() - startTime) / (nPairs * (long) nTrials);
System.out.println("Throughput: " + nsPerItem + " ns/item");
assertEquals(putSum.get(), takeSum.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static void assertEquals(int a, int b) {
if (a != b) {
throw new RuntimeException(a + " is not equals " + b);
}
}

private static int xorShift(int seed) {
seed ^= seed << 6;
seed ^= seed >>> 21;
seed ^= (seed << 7);
return seed;
}

class Producer implements Runnable {

@Override
public void run() {
try {
int seed = (this.hashCode() ^ (int) System.nanoTime());
int sum = 0;
barrier.await();
for (int i = nTrials; i > 0; --i) {
bq.put(seed);
sum += seed;
seed = xorShift(seed);
}
putSum.getAndAdd(sum);
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

class Consumer implements Runnable {

@Override
public void run() {
try {
barrier.await();
int sum = 0;
for (int i = nTrials; i > 0; --i) {
sum += bq.take();
}
takeSum.getAndAdd(sum);
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

}


上面这个实验的结果这里就不贴了,欢迎大家去实验。
做过[url=http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html]http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html[/url]这个实验的同学应该不容易发现,如果只采用lock&unlock与synchronized差别的确不大。

所以我只能妄断是条件signalAll&await的功劳,或许因为试验方式不对,或者的确是因为这个原因,终究我还没弄透。

signalAll&await的实现原理,这里有些讲解[url=http://www.goldendoc.org/2011/06/juc_condition/]http://www.goldendoc.org/2011/06/juc_condition/[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值