多线程(五)Lock 和 ReentrantLock

线程锁是用来实现同步机制的,前面讲到过使用synchronized关键字来实现同步。

使用这个关键字实现的同步块有一些缺点:

(1)锁只有一种类型

(2)线程得到锁或者阻塞

(3)不能实现很好的并发

为了解决如上的各种问题,后来又提出了一种更为复杂的锁 - 线程锁。

线程锁可以在几个方面进行提升:

(1)添加不同类型的锁,如读取锁和写入锁(主要实现类为ReentrantReadWriteLock类)

(2)对锁的阻塞没有限制,即可以在一个方法中上锁,在另外一个方法中解锁。

(3)如果线程得不到锁,比如锁由另外一个线程持有,就允许该线程后退或继续执行,或者做其他事情 - 使用类中提供的tryLock()方法

(4)允许线程尝试取锁,并可以在超过等待时间后放弃。

1、下面来认识一下一个简单的线程锁 - Lock锁。

public interface Lock {

/*    获取锁。如果锁不获取,在获得锁之前,该线程将一直处于休眠状态。 
    */
    void lock();
/*    如果当前线程未被中断,则获取锁。如果锁可用,则获取锁,并立即返回。
    如果锁不可用,则该线程将一直处于休眠状态,直到:
    (1) 锁由当前线程获得;或者 
    (2)其他某个线程中断当前线程。
    注意:如果当前线程,
    (1)在进入此方法时已经设置了该线程的中断状态;或者 
    (2)在获取锁时被中断,并且支持对锁获取的中断, 
    则将抛出 InterruptedException,并清除当前线程的已中断状态。    
     */
    void lockInterruptibly() throws InterruptedException;
/*    仅在调用时,锁为空闲状态才获取该锁。 
    如果锁可用,则获取锁,并立即返回值 true。
    如果锁不可用,则此方法将立即返回值 false。
    此方法的典型使用语句如下: 
      Lock lock = ...;
      if (lock.tryLock()) {
          try {
              // manipulate protected state
          } finally {
              lock.unlock();
          }
      } else {
          // perform alternative actions
      }
     此用法可确保如果获取了锁,则会释放锁,如果未获取锁,则不会试图将其释放。
     */
    boolean tryLock();
/*    如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。 
    如果锁可用,则此方法将立即返回值 true。
    如果锁不可用,该线程将一直处于休眠状态:直到下面三种情况出现 
    (1)锁由当前线程获得;或者 
    (2)其他某个线程中断当前线程,并且支持对锁获取的中断;或者 
    (3)已超过指定的等待时间 
    如果获得了锁,则返回值 true。 
    注意:如果当前线程: 
    (1)在进入此方法时已经设置了该线程的中断状态;或者 
    (2)在获取锁时被中断,并且支持对锁获取的中断, 
    则将抛出 InterruptedException,并会清除当前线程的已中断状态。 
    如果超过了指定的等待时间,则将返回值 false。
    如果 time 小于等于 0,该方法将完全不等待。 
    time为等待时长,unit为time参数的时间单位
     */
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

/*    释放锁。
     */
    void unlock();

/*    返回绑定到此 Lock 实例的新 Condition 实例。 
    在等待条件前,锁必须由当前线程保持。调用 Condition.await() 将在等待前以原子方式释放锁,
    并在等待返回前重新获取锁。 
     */
    Condition newCondition();
}

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。

锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。

synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中,Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。而Lock需要自己调用unlock()手动释放锁,否则会产生死锁。锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。

2、Lock的实现类ReentrantLock

首先说一下ReentrantLock的内置类Sync,而Sync 是extends AbstractQueuedSynchronizer

猜你喜欢

转载自blog.csdn.net/xiao1_1bing/article/details/81348240