`
fp1203
  • 浏览: 3281 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

synchronized & ReentrantLock 的一点疑问

阅读更多
经过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/
分享到:
评论

相关推荐

    第15讲 synchronized和ReentrantLock有什么区别呢?1

    在Java编程中,synchronized和ReentrantLock都是用于实现线程同步的重要工具,它们在并发控制方面扮演着关键角色。然而,两者之间存在一些显著的区别,这些差异体现在功能、灵活性、性能以及使用场景上。 首先,...

    并发编程之JMM&amp;amp;synchronized&amp;amp;volatile详解.pdf

    JMM规定了 volatile 变量、synchronized 关键字以及其他并发原语的行为。 【volatile关键字】在Java中,volatile是一个关键字,用于标记变量为共享变量,确保所有线程都能看到该变量的最新值。当一个变量被声明为...

    ReentrantLock与synchronized

    在Java多线程编程中,`ReentrantLock`和`synchronized`都是用于实现线程同步的重要工具,确保在并发环境中数据的一致性和正确性。两者虽然都能实现互斥访问,但在功能、性能以及使用场景上有所不同。下面我们将深入...

    简单聊聊Synchronized和ReentrantLock锁.docx

    本文将深入探讨Synchronized关键字锁和ReentrantLock锁的异同、功能特性以及它们在实际应用中的适用场景。 首先,Synchronized是一种内置的Java关键字,它提供了简单而强大的线程同步机制。当一个线程进入一个由...

    第15讲丨synchronized和ReentrantLock有什么区别呢?.html

    第15讲丨synchronized和ReentrantLock有什么区别呢?.html

    22 到底哪把锁更适合你?—synchronized与ReentrantLock对比.pdf

    在Java中,有两种主要的锁机制:内置的`synchronized`关键字和显式的`ReentrantLock`类。这两者各有优劣,适用于不同的场景。下面我们将详细讨论它们的区别、性能、特性以及使用上的差异。 1. **功能对比**: - `...

    java Thread & synchronized & concurrent 线程、同步、并发

    为了解决这一问题,Java提供了更细粒度的锁,如`java.util.concurrent.locks.ReentrantLock`,它具有与`synchronized`相似的功能,但提供了更多的灵活性,如可中断的等待、定时等待和尝试获取锁。 此外,`java.util...

    并发编程之synchronized&Lock&AQS详解(1)1

    2. `Lock`:`Lock`接口及其实现类如`ReentrantLock`提供了更细粒度的锁控制,提供了比`synchronized`更多的功能,如可中断的获取锁、尝试非阻塞获取锁以及读写锁等。`Lock`不是内置锁,它需要显式地获取和释放锁,...

    wangwang4git#just-do#简单说说Synchronized,ReentrantLock1

    背景,应该就是Synchronized的缺点Synchronized产生原因,原子性(Atomicity)与可见性(visibility),其中可见性涉及到JM

    ReentrantLock与synchronized区别

    java语言 并发编程 ReentrantLock与synchronized区别 详解

    synchronized ReentrantLock volatile Atomic 原理分析.docx

    《Java并发编程:synchronized、ReentrantLock、volatile与Atomic深度解析》 在Java多线程编程中,正确地管理共享资源是至关重要的。本文将深入探讨四种关键的并发控制机制:synchronized关键字、ReentrantLock(可...

    ReentrantLock 与 synchronized 简介

    ### ReentrantLock 与 synchronized 的比较 #### 一、引言 在Java中,多线程和并发控制一直是程序员关注的重点。随着Java的发展,其语言本身及标准库提供了丰富的工具来帮助开发者处理并发问题。其中,`...

    Java实习生面试复习(七):synchronized和ReentrantLock的学习

    Java并发编程中,`synchronized`关键字和`ReentrantLock`是两个重要的同步控制工具,它们主要用于保证多线程环境下的数据一致性与线程安全。本文将深入探讨这两个概念,了解它们的实现原理以及区别。 首先,`...

    Lock、Synchoronized和ReentrantLock的使用

    ReentrantLock 的性能比 Synchronized 略微差一点,但是在资源竞争激烈的情况下,ReentrantLock 的性能可以维持常态。ReentrantLock 的优点是提供了多种同步方式,且可以在激烈竞争的情况下维持常态。 三、Atomic ...

    深入java并发编程,使用ReentrantLock和 Synchronized加锁

    在Java并发编程中,理解和熟练使用同步机制是至关重要的,这包括了`ReentrantLock`和`synchronized`关键字。这两个工具都是为了确保多线程环境中的数据一致性与安全性,防止出现竞态条件和死锁等问题。 `...

    Java多线程之synchronized&volatile基础篇

    除此之外,Java还提供了其他类型的锁,如`ReentrantLock`,它具有与`synchronized`类似的功能,但提供了更高级的特性,如可中断的锁等待、定时锁等待和公平锁等。 `volatile`关键字是另一个与多线程相关的概念。它...

    ReentrantLock解析

    与synchronized关键字相比,ReentrantLock提供了更高的灵活性,如尝试加锁、定时加锁和公平锁等功能。本文将深入探讨ReentrantLock的实现原理,主要涉及其内部类AbstractQueuedSynchronizer(AQS)和Unsafe工具类。 ...

Global site tag (gtag.js) - Google Analytics