Lock

作者: kindol | 来源:发表于2018-07-30 23:58 被阅读0次

    lock的两个子类——ReentrantLock和ReentrantReadWriteLock

    ReentrantLock

    相比synchronized功能更加强大

    用法

    调用ReentrantLock的lock方法加锁,unlock方法解锁(一般在finally中写unlock)

    Object中的wait()、wait(long)等价于Condition中的await()、await(long time, TimeUnit unit)

    Object中的notify()、notifyAll()等价于Condition中的singal()、signalAll()

    使用Condition实现等待/通知

    ReentrantLock可以实现如果关键字synchronized与wait、notify等的功能,但需要借助Condition对象,使用Condition可以有更好的灵活性——比如多路通知,即可以在一个Lock对象里面创建多个Condition(即对象监视器)实例,,编程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更有灵活性。

    使用notify/notifyAll,被通知的线程是JVM选择的,而ReentrantLock结合Condition类可以实现“选择性通知”,事实上,synchronized相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它一个对象身上。线程开始notifyAll的时候,需要通知所有的waiting线程,产生效率问题。

    实现通知部分线程:

    private Lock lock = new ReentrantLock();
    private Condition cA = lock.newCondition();
    private Condition cB = lock.newCondition();
    ...
    
    在某wait函数中:
    lock.lock();
    conditionA.await();
    
    在某notify函数中:
    lock.lock();
    conditionA.signalAll();
    

    公平锁与非公平锁

    公平锁:线程获取锁的顺序是按照线程加锁的顺序来分配的,类似FIFO,但只是大部分线程按照FIFO

    非公平锁:未必按照FIFO,可能导致部分线程永远获取不到锁

    Lock lock = new ReentrantLock(isFair)
    

    通过设置如上的isFair判断是否为公平锁(默认情况下,ReentrantLock为非公平锁);当持有锁的时间或者请求锁的时间较长的时候,使用公平锁好一些,因为非公平锁的插队带来的效率提升此时可能不会有

    非公平锁的性能优于公平锁,原因如下:

    • 从线程进入了RUNNABLE状态到run状态是要比较久的时间的。而且,在一个锁释放之后,其他的线程会需要重新来获取锁。其中经历了持有锁的线程释放锁,其他线程从挂起恢复到RUNNABLE状态,其他线程请求锁,获得锁,线程执行,这一系列步骤。如果这个时候,存在一个线程直接请求锁,可能就避开挂起到恢复RUNNABLE状态的这段消耗,所以性能更优化。 相当于等待一个阻塞的进程和一个就绪的进程进入运行使用CPU的状态
    • 公平锁需要多加入一个条件判断

    getHoldCount()、getQueueLength()、getWaitQueueLength()的测试

    • getHoldCount()

      查询当前线程保持此锁定的次数,也就是调用lock方法的次数

    • getQueueLength()

      返回正等待获取此锁定的线程估计数,比如有5个线程,1个线程首先执行await()方法,调用此函数的返回值是4,说明有4个线程同时在等待lock的释放

    • getWaitQueueLength(Condition)

      回等待与此锁相关的给定条件Condition的线程估计数,比如5个线程,每个贤臣都执行了同一个Condition的await方法,则调用此函数的返回值为5

    hasQueuedThread、hasQueuedThreads、hasWaiters的测试

    • hasQueuedThread(Thread)

      查询指定的线程是否在等待获取此锁定

    • hasQueuedThreads()

      查询是否有线程在等待获取此锁定

    • hasWaiters(Condition)

      查询是否有线程在等待与此锁相关的condition条件

    isFair()、isHeldByCurrentThread()、isLocked的测试

    • isFair()

      判断是否为公平锁

    • isHeldByCurrentThread()

      查询当前线程是否保持此锁定,一般用于unlock前的条件判断

    • isLocked()

      判断此锁是否由任意线程持有

    lockInterruptibly()、tryLock()、tryLock(long timeout, TimeUnit unit)的测试

    • lockInterruptibly()

      如果当前线程未被中断,则获取锁定;否则抛出异常(可以利用此终止异常)

    • tryLock()

      调用时锁定未被另一个线程持有的情况下,才获取此锁定

    • tryLock(long timeout, TimeUnit unit)

      如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。

    ReentrantReadWriteLock类

    类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock方法后面的任务,虽然安全,但效率低。

    而ReentrantReadWriteLock类可以在某些不需要操作实例变量的方法中,使用读写锁来提高方法的代码运行速度。

    读写锁有两个锁:读——共享锁,写——排它锁。

    使用

    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    
    lock.readLock.lock()
    

    则可以有多个线程共享读

    如果把readLock改成writeLock,则将会导致读写、写写互斥

    相关文章

      网友评论

          本文标题:Lock

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