Java 多线程:Lock接口(接口方法分析,ReentrantLock,ReadWriteLock

前言


当咱们了解了多线程生成的缘由以后,会有相应的解决办法,最典型的就是 synchronized 和 lock。lock能够说是 synchronized 的一个替代品,synchronized 能作的事,lock 基本均可以作,并且能作得更好。他们的一些区别是:java

  • lock在获取锁的过程能够被中断。
  • lock能够尝试获取锁,若是锁被其余线程持有,则返回 false,不会使当前线程休眠。
  • lock在尝试获取锁的时候,传入一个时间参数,若是在这个时间范围内,没有得到锁,那么就是终止请求。
  • synchronized 会自动释放锁,lock 则不会自动释放锁。

这样能够看到,lock 比起 synchronized 具备更细粒度的控制。可是也不是说 lock 就彻底能够取代 synchronized,由于 lock 的学习成本,复杂度等方面要比 synchronized 高,对于初级 java 程序员,使用 synchronized 的风险要比 lock 低。程序员

目录


  • Lock 接口方法分析
  • RentrantLock
  • ReadWriteLock

Java 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();
}

lock,unlock 方法

lock() 能够用于对一段代码进行加锁,这样别的代码在锁释放以前须要进行等待,须要注意,lock不会像 synchronized 那样自动释放锁,因此:必定要放在 try-finally块中,保证锁的释放。 例如:并发

try {
    lock.lock();
    ......
} finally {
    lock.unlock();  
}

tryLock 方法

  • tryLock():尝试得到锁,若是成功,返回 true,不然,返回 false。
  • tryLock(long time,TimeUnit unit):在必定的时间内尝试得到锁,而且在这段时间直接能够被打断。若是成功得到,那么将返回 true,不然,返回 false。

lockInterruptibly 方法

这里首先须要了解两个概念才能更好的理解这个方法:函数

  • 线程的打扰机制
  • Thread类的interrupt,interrupted,isInterrupted方法的区别

对于线程的打扰机制,每一个线程都有一个打扰标志。源码分析

  • 若是线程在sleep或wait,join,此时若是别的进程调用此进程的 interrupt()方法,此线程会被唤醒并被要求处理InterruptedException;
  • 若是线程在运行,则不会收到提醒。可是此线程的 “打扰标志”会被设置。

因此说,对于 interrupt() 方法:不会中断一个正在运行的线程。学习

对于 interrupt,interrupted,isInterrupted方法的区别:this

interrupt 方法上面有说到了。对于 interrupted 和 isInterrupted 方法,stackoverflow 说得很好了:线程

interrupted() is static and checks the current thread. isInterrupted() is an instance method which checks the Thread object that it is called on.code

A common error is to call a static method on an instance.

Thread myThread = ...; if (myThread.interrupted()) {} // WRONG! This might not be checking myThread. if (myThread.isInterrupted()) {} // Right!

Another difference is that interrupted() also clears the status of the current thread. In other words, if you call it twice in a row and the thread is not interrupted between the two calls, the second call will return false even if the first call returned true.

The Javadocs tell you important things like this; use them often!

下面再介绍下 lockInterruptibly 方法:

当经过这个方法去获取锁时,若是线程正在等待获取锁,则这个线程可以响应中断,即中断线程的等待状 态。例如当两个线程同时经过lock.lockInterruptibly()想获取某个锁时,倘若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法可以中断线程B的等待过程。

newCondition()

用于获取一个 Conodition 对象。Condition 对象是比 Lock 更细粒度的控制。要很好的理解 condition,我的以为必需要知道,生产者消费者问题。

简单来讲就是,咱们都了解生产者在缓冲区满了的时候须要休眠,此时会再唤起一个线程,那么你此时唤醒的是生成者仍是消费者呢,若是是消费者,很好;可是若是是唤醒生产者,那还要再休眠,此时就浪费资源了。condition就能够用来解决这个问题,能保证每次唤醒的都是消费者。具体参考:Java 多线程:condition关键字

lock 方法大致就介绍到这里。

ReentrantLock


可重入锁:指同一个线程,外层函数得到锁以后,内层递归函数仍有得到该锁的代码,可是不受影响。

**可重入锁的最大做用就是 能够避免死锁。**例如:A线程有两个方法 a 和 b,其中 a 方法会调用 b 方法,假如 a,b 两个方法都须要得到锁,那么首先 a 方法先执行,会得到锁,此时 b方法将永远得到不了锁,b 方法将一直阻塞住, a 方法因为 b 方法没有执行完,它自己也 不释放锁,此时就会形成一个死锁。 ReentrantLock 就是一个可重入锁。真正使用锁的时候,通常是 Lock lock = new ReentrantLock();而后 使用 Lock 接口方法。

ReadWriteLock


接口代码以下:

public interface ReadWriteLock {  
    Lock readLock();  
    Lock writeLock();  
}

ReadWriteLock 能够算是 Lock 的一个细分,合理使用有利于提升效率。好比说, 对于一个变量 i, A,B 线程同时读,那么不会形成错误的结果,因此此时是容许并发,可是若是是同时写操做,那么则是有可能形成错误。因此真正使用的时候,可使用细分须要的是读锁仍是写锁,再相应地进行加锁。

Ps:从代码也能够看出,ReadWriteLock 和 Lock 没有关系,既不继承,也不是实现。

相关文章
相关标签/搜索