zoukankan      html  css  js  c++  java
  • ReentrantLock和读写锁

    在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock.

    ReentrantLock概况

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

    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使用

     
            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对象,其中一个用于读操作,而另外一个用于写操作。

    1.  
      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();
      }
       
    • 释放优先
    • 读线程插队
    • 重入性
    • 降级
    • 升级
    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();
            }
        }
    }
    休闲玩家 佛系更博
  • 相关阅读:
    idea 从svn导入项目遇到的错误
    用sql语句处理字符串以逗号截开分别获取值
    tree grid 实现编辑保存然后整体存入数据库
    EasyUI的TreeGrid的json格式,树状图显示问题
    vue.js--菜鸟级入门
    Django3.0知识笔记——WSGI&ASGI是什么?
    open stack
    shell脚本简介及常用文本编辑命令
    shell脚本之变量与运算符
    shell编程之流程控制(for、while、case、break、continue)
  • 原文地址:https://www.cnblogs.com/yuyuchen/p/9094861.html
Copyright © 2011-2022 走看看