java并发系列四(ReentranLock,并发工具类)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lc138544/article/details/84635622

一,ReentranLock详解

在上篇博客(java并发系列三),我们已经比较细的剖析了AQS的实现,而ReentranLock就是基于AQS实现的,具体的源码我们这里就不贴出来一一详解了。

1,ReentranLock与Synchronize比较

ReentranLock是Lock接口的实现类,先附上Lock接口源码

public interface Lock {

    void lock();

    void lockInterruptibly() throws InterruptedException;

    boolean tryLock();

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    void unlock();

    Condition newCondition();
}

1,lock()获取锁,没有获取一直等待,无返回值
2,lockInterruptibly()获取锁一直等待,无返回值,但是可以被thread.interrupt()方法中断,抛出异常(可中断这一点是Synchronize关键字做不到的)
3,tryLock()获取锁,不等待,返回是否获取成功
4,tryLock(long time, TimeUnit unit)获取锁,没有获取等待指定时间,返回是否获取成功,等待时候可以被thread.interrupt()方法中断,抛出异常
5,unlock()释放锁
6,newCondition(),构造一个显示的Condition对象实现线程间的交互。

相对于Synchronize,ReentranLock提供了更丰富的功能:可定时的锁等待,可中断的锁等待,公平性,非块结构的加锁。讲到这里,大家肯定会有疑问,为什么不放弃内置锁,转而全部使用ReentranLock。因为现在好多程序都使用了Synchronize,如果将两种机制混合使用,容易让人困惑。而且Synchronize也在不断的优化。
所以记住了:仅当内置锁无法满足需求时,再使用ReentranLock。

2,公平锁与非公平锁

ReentranLock分为公平锁与非公平锁。默认情况下是非公平锁,即可重入的。
非公平锁:当一个线程请求非公平的锁时,如果发出请求的同时该锁的状态变为可用,那么这个线程将跳过队列中所有等待的线程去获得这个锁。
公平锁与非公平锁相对,先进先出,老老实实在队列中排队等待。
在大多数情况下,非公平锁比公平锁的性能高的多,公平锁由于在挂起和恢复线程时存在的开销而极大降低性能。

4,读-写锁

ReentrantLock是一种标准的互斥锁,每次最多只有一个线程能持有锁。读写锁不一样,暴露了两个Lock对象,其中一个用于读操作,而另外一个用于写操作。读写锁适用于读多写少的情况。读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排它锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。
可选择实现:
释放优先
读线程插队
重入性
降级
升级
ReentrantReadWriteLock实现了ReadWriteLock接口,构造器提供了公平锁和非公平锁两种创建方式。读写锁适用于读多写少的情况,可以实现更好的并发性。
例子

public class ReadWriteMap<K, V> {
    private Map<K, V> map;
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();

    public ReadWriteMap(Map<K, V> map) {
        this.map = map;
    }

    public V get(K key) {
        readLock.lock();
        try {
            return map.get(key);
        } finally {
            readLock.unlock();
        }
    }

    public void put(K key, V value) {
        writeLock.lock();
        try {
            map.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }
}

二,并发工具类详解

这三个工具,我只是写了一下自己的理解,想要更深入的理解可以参考java并发编程实战。
闭锁CountdownLatch
闭锁用来确保某些活动直到其他活动都完成后再继续执行,CountdownLatch是一种灵活的闭锁实现,内部源码也是基于AQS实现的。这个工具还是比较简单的。。。。我就不详说了。。。具体参考一下java并发编程实战把
信号量Semaphore
计数信号量用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。我在学习这个的时候,有句话讲的很通俗易懂,这就相当于一个房间,这个房间里最多能有n个人,进去一个即相当于调用acquire(),出来一个相当于release().如果满了,必须空出来才能重新进去。
栅栏CyclicBarrier
栅栏和闭锁非常类似,它能阻塞一组线程,知道某个事件的发生。区别:闭锁用于等待事件,栅栏用于等待线程。CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。

展开阅读全文

没有更多推荐了,返回首页