经过JDK1.6对synchronized的进一步优化,通常情况下,synchronized与lock & unlock 效率差别不大,如果大家做一下简单实验应该不容易得出,见
http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html中的实验,但在做下面这个实验时,发现两者效率上还是有些区别的。
这是一个最简单的阻塞队列的实现,分别采用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);
}
}
}
}
上面这个实验的结果这里就不贴了,欢迎大家去实验。
做过
http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html这个实验的同学应该不容易发现,如果只采用lock&unlock与synchronized差别的确不大。
所以我只能妄断是条件signalAll&await的功劳,或许因为试验方式不对,或者的确是因为这个原因,终究我还没弄透。
signalAll&await的实现原理,这里有些讲解
http://www.goldendoc.org/2011/06/juc_condition/
分享到:
相关推荐
在Java编程中,synchronized和ReentrantLock都是用于实现线程同步的重要工具,它们在并发控制方面扮演着关键角色。然而,两者之间存在一些显著的区别,这些差异体现在功能、灵活性、性能以及使用场景上。 首先,...
JMM规定了 volatile 变量、synchronized 关键字以及其他并发原语的行为。 【volatile关键字】在Java中,volatile是一个关键字,用于标记变量为共享变量,确保所有线程都能看到该变量的最新值。当一个变量被声明为...
在Java多线程编程中,`ReentrantLock`和`synchronized`都是用于实现线程同步的重要工具,确保在并发环境中数据的一致性和正确性。两者虽然都能实现互斥访问,但在功能、性能以及使用场景上有所不同。下面我们将深入...
本文将深入探讨Synchronized关键字锁和ReentrantLock锁的异同、功能特性以及它们在实际应用中的适用场景。 首先,Synchronized是一种内置的Java关键字,它提供了简单而强大的线程同步机制。当一个线程进入一个由...
第15讲丨synchronized和ReentrantLock有什么区别呢?.html
在Java中,有两种主要的锁机制:内置的`synchronized`关键字和显式的`ReentrantLock`类。这两者各有优劣,适用于不同的场景。下面我们将详细讨论它们的区别、性能、特性以及使用上的差异。 1. **功能对比**: - `...
为了解决这一问题,Java提供了更细粒度的锁,如`java.util.concurrent.locks.ReentrantLock`,它具有与`synchronized`相似的功能,但提供了更多的灵活性,如可中断的等待、定时等待和尝试获取锁。 此外,`java.util...
2. `Lock`:`Lock`接口及其实现类如`ReentrantLock`提供了更细粒度的锁控制,提供了比`synchronized`更多的功能,如可中断的获取锁、尝试非阻塞获取锁以及读写锁等。`Lock`不是内置锁,它需要显式地获取和释放锁,...
背景,应该就是Synchronized的缺点Synchronized产生原因,原子性(Atomicity)与可见性(visibility),其中可见性涉及到JM
java语言 并发编程 ReentrantLock与synchronized区别 详解
《Java并发编程:synchronized、ReentrantLock、volatile与Atomic深度解析》 在Java多线程编程中,正确地管理共享资源是至关重要的。本文将深入探讨四种关键的并发控制机制:synchronized关键字、ReentrantLock(可...
ReentrantLock 的性能比 Synchronized 略微差一点,但是在资源竞争激烈的情况下,ReentrantLock 的性能可以维持常态。ReentrantLock 的优点是提供了多种同步方式,且可以在激烈竞争的情况下维持常态。 三、Atomic ...
### ReentrantLock 与 synchronized 的比较 #### 一、引言 在Java中,多线程和并发控制一直是程序员关注的重点。随着Java的发展,其语言本身及标准库提供了丰富的工具来帮助开发者处理并发问题。其中,`...
Java并发编程中,`synchronized`关键字和`ReentrantLock`是两个重要的同步控制工具,它们主要用于保证多线程环境下的数据一致性与线程安全。本文将深入探讨这两个概念,了解它们的实现原理以及区别。 首先,`...
在Java并发编程中,理解和熟练使用同步机制是至关重要的,这包括了`ReentrantLock`和`synchronized`关键字。这两个工具都是为了确保多线程环境中的数据一致性与安全性,防止出现竞态条件和死锁等问题。 `...
除此之外,Java还提供了其他类型的锁,如`ReentrantLock`,它具有与`synchronized`类似的功能,但提供了更高级的特性,如可中断的锁等待、定时锁等待和公平锁等。 `volatile`关键字是另一个与多线程相关的概念。它...
与synchronized关键字相比,ReentrantLock提供了更高的灵活性,如尝试加锁、定时加锁和公平锁等功能。本文将深入探讨ReentrantLock的实现原理,主要涉及其内部类AbstractQueuedSynchronizer(AQS)和Unsafe工具类。 ...