美文网首页
java并发ReentrantLock,Condition,Se

java并发ReentrantLock,Condition,Se

作者: 带着二娃去遛弯 | 来源:发表于2019-08-15 20:00 被阅读0次

    ReentrantLock
    在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从jdk1.6开始,Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。
    看一下ReentrantLock的接口:


    image.png

    简单的例子


    image.png

    运行结果:

    如果在不加锁的情况下运行结果,最终的数字不确定(接近10000000):

    ReenTrantLock独有的能力:
    ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
    ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
    ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
    中断机制
    来看一下ReentrantLock相对于synchronized的第一点特点:ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。


    image.png
    image.png

    运行结果:


    image.png

    公平锁
    在大多数情况下锁的申请都是非公平的,如果线程1首先申请的锁,之后线程2申请锁,当这把锁可用的时候,系统只会从这个锁的等待队列中随机挑选一个。这样容易造成某些线程饿死。而公平锁是排队的遵循先到先得的原则:


    image.png

    公平锁运行结果:


    image.png

    非公平锁运行结果:


    image.png

    Condition
    如果理解Object.wait()和Object.notify()那么Condition就比较好理解了,wait和notify是和synchronized关键字配合使用
    Condition接口的方法如下:


    image.png

    void await() throws InterruptedException
    当前线程进入等待状态,直到被通知(signal)或者被中断时,当前线程进入运行状态,从await()返回;

    void awaitUninterruptibly()

    当前线程进入等待状态,直到被通知,对中断不做响应;

    long awaitNanos(long nanosTimeout) throws InterruptedException
    在await()的返回条件基础上增加了超时响应,返回值表示当前剩余的时间,如果在nanosTimeout之前被唤醒,返回值 = nanosTimeout - 实际消耗的时间,返回值 <= 0表示超时;

    boolean await(long time, TimeUnit unit) throws InterruptedException

    同样是在await()的返回条件基础上增加了超时响应,与接口3不同的是:

    可以自定义超时时间单位;
    返回值返回true/false,在time之前被唤醒,返回true,超时返回false。

    boolean awaitUntil(Date deadline) throws InterruptedException

    当前线程进入等待状态直到将来的指定时间被通知,如果没有到指定时间被通知返回true,否则,到达指定时间,返回false;

    void signal()

    唤醒一个等待在Condition上的线程;

    void signalAll()

    唤醒等待在Condition上所有的线程。

    示例:


    image.png

    运行结果:

    和wait/notify一样,当线程使用condition.await()的时候,要求线程持有相关的锁,当线程调用condition.await()之后,这个线程会释放持有的锁,并进入等待状态。当调用notify()的时候系统会挑选一个等待在该条件下的线程并唤醒之。

    在JDK内部,重入锁和Condition被广泛使用,以ArrayBlockingQueue为例:


    image.png image.png image.png image.png

    信号量:Semaphore
    信号量为多个线程协作提供了更强大的控制方法,无论是ReentrantLock还是Synchronized一次都只允许一个线程访问一个资源。信号量允许多个线程同时访问同一个资源:
    看下Semaphore的接口定义:


    image.png

    有两个构造函数:


    image.png

    permits表示一次允许多少个线程, fair表示是否公平锁

    示例:

    image.png

    相关文章

      网友评论

          本文标题:java并发ReentrantLock,Condition,Se

          本文链接:https://www.haomeiwen.com/subject/wrytsctx.html