Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁

原文地址: https://www.jb51.net/article/64012.htm

简介

这篇文章主要介绍了Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁,本文讲解了ReentrantLock概况、Lock接口、Lock使用、轮询锁的和定时锁、公平性、可中断获锁获取操作等内容,需要的朋友可以参考下
在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock.

ReentrantLock概况

ReentrantLock是可重入的锁,它不同于内置锁, 它在每次使用都需要显示的加锁和解锁, 而且提供了更高级的特性:公平锁, 定时锁, 有条件锁, 可轮询锁, 可中断锁. 可以有效避免死锁的活跃性问题.ReentrantLock实现了。
java.util.concurrent.locks包:
在这里插入图片描述

Lock接口:

 public interface Lock {
          //获得锁(阻塞直到获得锁或者中断)
          void lock();
          //获取锁定,除非当前线程是 interrupted (阻塞直到获得锁或者中断抛异常)
          void lockInterruptibly() throws InterruptedException;
		 //只有在调用时才可以获得锁。 (只有锁可用时才获得,否则直接返回)
          boolean tryLock();

          //如果在给定的等待时间内是空闲的,并且当前的线程尚未得到 interrupted,则获取该锁。
          //(只有锁在指定时间内可用时才获得,否则直接返回,中断时抛异常)
          boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
		  //释放锁
          void unlock();

          //返回一个新Condition绑定到该实例Lock实例(返回一个绑定在这个锁上的条件)
          Condition newCondition();
  }
  

Thrad类:
public static boolean interrupted()测试当前线程是否中断。 该方法可以清除线程的中断状态 。
换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false
(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。
忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。
结果
true如果当前线程已被中断; false否则。
另请参见:
isInterrupted()

Lock使用

        Lock lock = new ReentrantLock();
        lock.lock();//获取锁
        try{
            //更新对象状态
        }finally{
            //这里注意,一定要有finally代码块去解锁
            //否则容易造成死锁等活跃性问题
            lock.unlock();//释放锁
        }

ReentrantLock特性

轮询锁的和定时锁
可轮询和可定时 的锁请求是通过 tryLock() 方法实现的,和无条件获取锁不一样.
ReentrantLock可以有灵活的容错机制.死锁 的很多情况是由于顺序锁引起的, 不同线程在试图获得锁的时候阻塞,并且不释放自己已经持有的锁, 最后造成死锁.
tryLock() 方法在试图获得锁的时候,如果该锁已经被其它线程持有,则按照设置方式立刻返回,而不是一直阻塞等下去,同时在返回后释放自己持有的锁.可以根据返回的结果进行重试或者取消,进而避免死锁的发生.

公平性
ReentrantLock构造函数中提供 公平性锁和非公平锁(默认) 两种选择。
**所谓公平锁,**线程将按照他们发出请求的顺序来获取锁,不允许插队;
但在 非公平锁 上,则允许插队:当一个线程发生获取锁的请求的时刻,如果这个锁是可用的,那这个线程将跳过所在队列里等待线程并获得锁。我们一般希望所有锁是非公平的。因为当执行加锁操作时,公平性将讲由于线程挂起和恢复线程时开销而极大的降低性能。
考虑这么一种情况:
A线程持有锁,B线程请求这个锁,因此B线程被挂起;A线程释放这个锁时,B线程将被唤醒,因此再次尝试获取锁;与此同时,C线程也请求获取这个锁,那么C线程很可能在B线程被完全唤醒之前获得、使用以及释放这个锁。这是种双赢的局面,B获取锁的时刻(B被唤醒后才能获取锁)并没有推迟,C更早地获取了锁,并且吞吐量也获得了提高。在大多数情况下,非公平锁的性能要高于公平锁的性能。

可中断获锁获取操作
lockInterruptibly方法能够在获取锁的同时保持对中断的响应,因此无需创建其它类型的不可中断阻塞操作。

读写锁ReadWriteLock
​ReentrantLock 是一种标准的互斥锁,每次最多只有一个线程能持有锁。
读写锁不一样,暴露了两个Lock对象,其中一个用于读操作,而另外一个用于写操作。

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
     //返回用于阅读的锁
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
     //返回用于写入的锁
    Lock writeLock();
}

可选择实现:

1.释放优先
2.读线程插队
3.重入性
4.降级
5.升级

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();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值