zoukankan      html  css  js  c++  java
  • 关于ReentrantLock锁的一些理解

     简介

    ReentrantLock常常对比着synchronized来分析,我们先对比着来看然后再一点一点分析。

    (1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

    (2)synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

    (3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

    场景1:如果发现该操作已经在执行中则不再执行(有状态执行)

    a、用在定时任务时,如果任务执行时间可能超过下次计划执行时间,确保该有状态任务只有一个正在执行,忽略重复触发。
    b、用在界面交互时点击执行较长时间请求操作时,防止多次点击导致后台重复执行(忽略重复触发)。

    以上两种情况多用于进行非重要任务防止重复执行,(如:清除无用临时文件,检查某些资源的可用性,数据备份操作等)

    这里写图片描述

     

    场景2:如果发现该操作已经在执行,等待一个一个执行(同步执行,类似synchronized)

    这种比较常见大家也都在用,主要是防止资源使用冲突,保证同一时间内只有一个操作可以使用该资源。
    但与synchronized的明显区别是性能优势(伴随jvm的优化这个差距在减小)。同时Lock有更灵活的锁定方式,公平锁与不公平锁

    ReentrantLock默认情况下为不公平锁

    不公平锁与公平锁的区别:
    公平情况下,操作会排一个队按顺序执行,来保证执行顺序。(会消耗更多的时间来排队)
    不公平情况下,是无序状态允许插队,jvm会自动计算如何处理更快速来调度插队。(如果不关心顺序,这个速度会更快)

    这里写图片描述

    场景3:如果发现该操作已经在执行,则尝试等待一段时间,等待超时则不执行(尝试等待执行)

    这种其实属于场景2的改进,等待获得锁的操作有一个时间的限制,如果超时则放弃执行。
    用来防止由于资源处理不当长时间占用导致死锁情况(大家都在等待资源,导致线程队列溢出)。

    这里写图片描述

    场景4:如果发现该操作已经在执行,等待执行。这时可中断正在进行的操作立刻释放锁继续下一操作

    synchronized与Lock在默认情况下是不会响应中断(interrupt)操作,会继续执行完。lockInterruptibly()提供了可中断锁来解决此问题。(场景2的另一种改进,没有超时,只能等待中断或执行完毕)

    这种情况主要用于取消某些操作对资源的占用。如:(取消正在同步运行的操作,来防止不正常操作长时间占用造成的阻塞)

    这里写图片描述

     

    下面是ReentrantLock的一个代码示例

    //: concurrency/AttemptLocking.java  
    // 以下是ReentrantLock中断机制的一个代码实现、如果换成synchronized就会出现死锁  
    import java.util.concurrent.*;  
    import java.util.concurrent.locks.*;  
    
    public class AttemptLocking {  
        private ReentrantLock lock = new ReentrantLock();  
    
        public void untimed() {  
            boolean captured = lock.tryLock();  
            try {  
                System.out.println("tryLock(): " + captured);  
            } finally {  
                if (captured)  
                    lock.unlock();  
            }  
        }  
    
        public void timed() {  
            boolean captured = false;  
            try {  
                captured = lock.tryLock(2, TimeUnit.SECONDS);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
            try {  
                System.out.println("tryLock(2, TimeUnit.SECONDS): " + captured);  
            } finally {  
                if (captured)  
                    lock.unlock();  
            }  
        }  
    
        public static void main(String[] args) throws InterruptedException {  
            final AttemptLocking al = new AttemptLocking();  
            al.untimed(); // True -- 可以成功获得锁  
            al.timed(); // True --可以成功获得锁  
            //新创建一个线程获得锁并且不释放  
            new Thread() {  
                {  
                    setDaemon(true);  
                }  
    
                public void run() {  
                    al.lock.lock();  
                    System.out.println("acquired");  
                }  
            }.start();  
            Thread.sleep(100);// 保证新线程能够先执行  
            al.untimed(); // False -- 马上中断放弃  
            al.timed(); // False -- 等两秒超时后中断放弃  
        }  
    }  
  • 相关阅读:
    Maven安装与环境配置(Windows)
    Java配置----JDK开发环境搭建及环境变量配置
    js中的join(),reverse()与 split()函数用法解析
    Vue2.0 搭建Vue脚手架(vue-cli)
    vue: WebStorm设置快速编译运行
    优秀博客推荐
    Springboot读取自定义配置文件节点
    vue——报错:Cannot read property '__ob__' of undefined
    css——内容溢出显示垂直滚动条,内容不超出就不显示滚动条
    js——实现多选
  • 原文地址:https://www.cnblogs.com/mr-wuxiansheng/p/12997033.html
Copyright © 2011-2022 走看看