`
richard_lee
  • 浏览: 16029 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

并发锁及java.util.concurrent包浅析

阅读更多
    我们在处理并发操作的时候经常使用锁机制,大家常用的synchronized和Lock.
1.二者使用方式有所不同:
     synchronized可以在方法前或者代码块中,synchronized是java中的内置锁,由jvm控制锁的释放。
     Lock使用在代码块中,加锁之后需要显示的释放,一般在finally中释放锁,主要有两种锁ReentrantLock和ReentrantReadWriteLock。
2.二者都是互斥锁,也就是一次只能有一个对象持有该锁。
3.synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其   他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。
    Lock采用的是乐观锁方式,所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。是非阻塞的。
    一般情况下我们使用synchronized就可以满足并发控制,对应高性能的锁机制,我们可以使用ReentrantLock-可重入锁。
    java.util.concurrent提供了支持并发数据结构的操作,通过这些我们也可以了解ReentrantLock使用的情形。
ConcurrentHashMap:采用ReentrantLock进行并发控制。
LinkedBlockingDeque:双向阻塞队列,可以作为栈使用,采用ReentrantLock进行并发控制。
LinkedBlockingQueue:阻塞队列,采用ReentrantLock进行并发控制。
如:

/** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();

    /** Wait queue for waiting takes */
    private final Condition notEmpty = takeLock.newCondition();

    对于阻塞队列,主要是使用take()方法:返回并且移除队列头部元素,当队列中没有可用元素时,处于阻塞等待状态。
源代码如:

public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                notEmpty.await();
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

    可用看到,该方法通过可重入锁ReentrantLock进行并发控制的。其中Condition的
notEmpty.signal()表示唤醒等待中的线程,notEmpty.await()使当前的线程处于等待状态,直到被唤醒或者被中断。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics