Java ReentrantLock 详解_reentrantlock.trylock(5, timeunit.seconds)-程序员宅基地

技术标签: java  Android  

ReentrantLock 和 synchronized 的区别:

1.ReentrantLock 不需要代码块,在开始的时候lock,在结束的时候unlock 就可以了。

但是要注意,lock 是有次数的,如果连续调用了两次lock,那么就需要调用两次unlock。否则的话,别的线程是拿不到锁的。

    /**
     * 很平常的用锁 没有感觉reentrantlocak 的强大
     *
     * 如果当前线程已经拿到一个锁了 那么再次调用 会里面返回true
     * 当前线程的锁数量是 2个
     *
    */
    private void normalUse() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        new Thread("thread1"){
            @Override
            public void run() {
                super.run();
                LogToFile.log(TAG,"thread1 lock");
                reentrantLock.lock();
                reentrantLock.lock();
               
                LogToFile.log(TAG,"thread1 getHoldCount:"  + reentrantLock.getHoldCount() );

                try {
                    LogToFile.log(TAG,"thread1 run");

                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                 //如果说你的线程占了两个锁 一个没有释放 其他线程都拿不到这个锁
                 //上面lock 了两次 这里需要unLock 两次
                reentrantLock.unlock();
                reentrantLock.unlock();
                LogToFile.log(TAG,"thread1 unlock");
            }
        }.start();


        new Thread("thread2"){
            @Override
            public void run() {
                super.run();

                LogToFile.log(TAG,"thread2 lock");
                reentrantLock.lock();
                LogToFile.log(TAG,"thread2 run");

                reentrantLock.unlock();
                LogToFile.log(TAG,"thread2 unlock");

            }
        }.start();
    }

ReentrantLock trylock()

ReentrantLock trylock 会尝试去拿锁,如果拿得到,就返回true, 如果拿不到就返回false.这个都是立马返回,不会阻塞线程。
如果当前线程已经拿到锁了,那么trylock 会返回true.

    /**
     * trylock 不管能不能拿到锁 都会里面返回结果 而不是等待
     * tryLock 会破坏ReentrantLock 的 公平机制
     * 注意 如果没有拿到锁 执行完代码之后不要释放锁,
     * 否则会有exception
     *
     */
    private void UseTryLock() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        new Thread("thread1"){
            @Override
            public void run() {
                super.run();
                LogToFile.log(TAG,"thread1 lock");
                reentrantLock.lock();
                try {
                    LogToFile.log(TAG,"thread1 run");

                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                reentrantLock.unlock();
                LogToFile.log(TAG,"thread1 unlock");
            }
        }.start();


        new Thread("thread2"){
            @Override
            public void run() {
                super.run();

                LogToFile.log(TAG,"thread2 tryLock");
                boolean success = reentrantLock.tryLock();
                LogToFile.log(TAG,"thread2 run");

                if (success) {
                    reentrantLock.unlock();
                    LogToFile.log(TAG,"thread2 unlock");
                    //    java.lang.IllegalMonitorStateException
                    //        at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:123)
                    //        at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1235)
                    //        at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:429)

                }

            }
        }.start();
    }

ReentrantLock .tryLock(5, TimeUnit.SECONDS)

ReentrantLock 可以指定,尝试去获取锁,等待多长时间之后,如果还获取不到,那么就放弃。

    /**
     * tryLock(5, TimeUnit.SECONDS)
     * 如果5s之后 还拿不到锁  那么就不再堵塞线程,也不去拿锁了 执行执行下面的代码了
     */
    private void UseTryLockWhitTime() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        new Thread("thread1"){
            @Override
            public void run() {
                super.run();
                LogToFile.log(TAG,"thread1 lock");
                reentrantLock.lock();
                try {
                    LogToFile.log(TAG,"thread1 run");

                    Thread.sleep(1000 * 10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                reentrantLock.unlock();
                LogToFile.log(TAG,"thread1 unlock");
            }
        }.start();


        new Thread("thread2"){
            @Override
            public void run() {
                super.run();

                LogToFile.log(TAG,"thread2 tryLock");
                boolean success = false;
                try {
                    success = reentrantLock.tryLock(5, TimeUnit.SECONDS);
                    LogToFile.log(TAG,"thread2 run");

                    if (success) {
                        reentrantLock.unlock();
                        LogToFile.log(TAG,"thread2 unlock");
                        //    java.lang.IllegalMonitorStateException
                        //        at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:123)
                        //        at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1235)
                        //        at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:429)

                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

ReentrantLock .lock();

一旦调用了ReentrantLock .lock() ,如果你的线程被其他线程interrupt,那么你的线程并不会interrupt,而是继续等待锁。

    /**
     * lockInterruptibly() 和  lock 的区别是
     * 如果当前线程被Interrupt 了,那么lockInterruptibly 就不再等待锁了。直接会抛出来一个异常给你处理
     * 如果是lock 的话 就算 线程被其他的线程lockInterrupt 了,不管用,他还会继续等待锁
     */
    private void UseLockIntercepter() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        Thread thread = new Thread("thread1") {
            @Override
            public void run() {
                super.run();
                LogToFile.log(TAG, "thread1 lock");
                reentrantLock.lock();
                LogToFile.log(TAG, "thread1 run");
                if (reentrantLock.getHoldCount() != 0) {
                    reentrantLock.unlock();
                }
                LogToFile.log(TAG, "thread1 unlock");
            }
        };


        new Thread("thread2"){
            @Override
            public void run() {
                super.run();

                LogToFile.log(TAG,"thread2 tryLock");
                boolean success = false;
                try {
                    reentrantLock.lock();
                    thread.start();

                    thread.interrupt();
                    success = reentrantLock.tryLock(5, TimeUnit.SECONDS);
                    LogToFile.log(TAG,"thread2 run");

                    if (success) {
                        reentrantLock.unlock();
                        reentrantLock.unlock();
                        LogToFile.log(TAG,"thread2 unlock");
                        //    java.lang.IllegalMonitorStateException
                        //        at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:123)
                        //        at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1235)
                        //        at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:429)

                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

ReentrantLock .lockInterruptibly();

如果当前线程调用lockInterruptibly 这个方法去获取锁,当其他的线程把你的线程给interrupt 之后,那么你的线程就不再等待锁了,执行下面的代码。

    /**
     * lockInterruptibly() 和  lock 的区别是
     * 如果当前线程被Interrupt 了,那么lockInterruptibly 就不再等待锁了。直接会抛出来一个异常给你处理
     * 如果是lock 的话 就算 线程被其他的线程lockInterrupt 了,不管用,他还会继续等待锁
     */
    private void UseLockIntercepter2() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        Thread thread = new Thread("thread1") {
            @Override
            public void run() {
                super.run();
                LogToFile.log(TAG, "thread1 lock");
                try {
                    reentrantLock.lockInterruptibly();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    LogToFile.log(TAG, "thread1 lock InterruptedException ");

                }
                LogToFile.log(TAG, "thread1 run");
                if (reentrantLock.getHoldCount() != 0) {
                    reentrantLock.unlock();
                }
                LogToFile.log(TAG, "thread1 unlock");
            }
        };


        new Thread("thread2"){
            @Override
            public void run() {
                super.run();

                LogToFile.log(TAG,"thread2 tryLock");
                boolean success = false;
                try {
                    reentrantLock.lock();
                    thread.start();

                    thread.interrupt();
                    success = reentrantLock.tryLock(5, TimeUnit.SECONDS);
                    LogToFile.log(TAG,"thread2 run");

                    if (success) {
                        reentrantLock.unlock();
                        reentrantLock.unlock();
                        LogToFile.log(TAG,"thread2 unlock");
                        //    java.lang.IllegalMonitorStateException
                        //        at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:123)
                        //        at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1235)
                        //        at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:429)

                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

ReentrantLock newCondition()使用:

condition. 的await 相当于 object 的wait 方法,就是等待其他线程唤醒,但是调用之前必须要reentrantLock.lock(); 一下,不然会抛异常。

    /**
     * tryLock(5, TimeUnit.SECONDS)
     * 如果5s之后 还拿不到锁  那么就不再堵塞线程,也不去拿锁了 执行执行下面的代码了
     */
    private void UseCondition() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        Thread thread = new Thread("thread1") {
            @Override
            public void run() {
                super.run();

                try {
                    reentrantLock.lock();
                    LogToFile.log(TAG, "thread1 wait");
                    //await 其实是会释放锁的 其他的线程可以拿到锁 然后signal  不然的话岂不是要卡死?
                    condition.await();

                    LogToFile.log(TAG, "thread1 run");

                    Thread.sleep(1000 * 3);
                    condition.signalAll();
                    reentrantLock.unlock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LogToFile.log(TAG, "thread1 unlock");
            }
        };
        thread.start();


        Thread thread1 = new Thread("thread2") {
            @Override
            public void run() {
                super.run();
                //调用signal 之前一定要lock
                reentrantLock.lock();
                //就算没有人调用await 那么signal 方法也不会有什么问题
                condition.signal();

                try {
                    LogToFile.log(TAG, "thread2 wait");
                    condition.await();
                    LogToFile.log(TAG, "thread2 run");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                reentrantLock.unlock();
            }
        };
        thread1.start();
    }

Object wait方法使用:

wait 方法调用之前也要synchronized 一个锁。

    /**
     * 使用wait
     */
    private void UseWait() {
        ReentrantLock reentrantLock =  new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        new Thread("thread1"){
            @Override
            public void run() {
                super.run();

                try {
                    synchronized (condition) {
                        LogToFile.log(TAG,"thread1 wait");
                        condition.wait();
                    }

                    LogToFile.log(TAG,"thread1 run");

                    Thread.sleep(1000 * 10);
                    synchronized (condition) {
                        condition.notifyAll();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LogToFile.log(TAG,"thread1 unlock");
            }
        }.start();


        new Thread("thread2"){
            @Override
            public void run() {
                super.run();
                synchronized (condition) {
                    condition.notify();

                }
                try {
                    LogToFile.log(TAG,"thread2 wait");
                    synchronized (condition){
                        condition.wait();
                    }
                    LogToFile.log(TAG,"thread2 run");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

synchronized

synchronized 锁等待的线程,当被其他线程interrupt 的时候,并不会停止。

/**
 * synchronized 的锁,不能被中断
 */
public void testSyncInter(){
    Object lock = new Object();
    Thread thread = new Thread("thread1") {
        @Override
        public void run() {
            super.run();
            synchronized (lock) {
                LogToFile.log(TAG, "thread1 lock");
                LogToFile.log(TAG, "thread1 run");
            }
            LogToFile.log(TAG, "thread1 unlock");

        }
    };


    new Thread("thread2"){
        @Override
        public void run() {
            super.run();
            synchronized (lock) {
                LogToFile.log(TAG,"thread2 start");
                thread.start();
                thread.interrupt();

            }
            LogToFile.log(TAG,"thread2 run");
        }
    }.start();
}

BlockingQueue 就是使用ReentrantLock 实现的阻塞队列:

    /**
     * BlockingQueue  会阻塞当前的线程  等着其他线程放数据
     */
    public void testArrayBlockQueue(){
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(4);

        new Thread("thread1"){
            @Override
            public void run() {
                super.run();
                try {
                    LogToFile.log(TAG,"thread1 take");
                    blockingQueue.take();
                    LogToFile.log(TAG,"thread1 take  get");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        new Thread("thread2"){
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    LogToFile.log(TAG,"thread2 put");

                    //put 会阻塞 但是add 不会
                    blockingQueue.put(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

ArrayBlockingQueue 源码解析:

下面的代码,可以看到ArrayBlockingQueue 创建了ReentrantLock ,以及两个condition


    /** Main lock guarding all access */
    final ReentrantLock lock;

    /** Condition for waiting takes */
    private final Condition notEmpty;

    /** Condition for waiting puts */
    private final Condition notFull;

public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

当我们往里面放元素的时候,我们会对notFull 进行等待,因为队列不是空的了。

当出队列的时候,notFull.signal(); 也就是当前的队列不是满的了,可以放元素进去了。

    /**
     * Inserts the specified element at the tail of this queue, waiting
     * for space to become available if the queue is full.
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();
        return x;
    }

当我们往里面取元素的时候,如果队列是空的了,那么notEmpty 就要等待,当enqueue一个元素的时候,notEmpty 不是空就唤醒,那么take 就可以执行去拿元素了。

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

    private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        notEmpty.signal();
    }

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013270444/article/details/104951842

智能推荐

5个超厉害的资源搜索网站,每一款都可以让你的资源满满!_最全资源搜索引擎-程序员宅基地

文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎

Book类的设计(Java)_6-1 book类的设计java-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java

基于微信小程序的校园导航小程序设计与实现_校园导航微信小程序系统的设计与实现-程序员宅基地

文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。

有状态和无状态登录

传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

随便推点

控制对象的特性_控制对象特性-程序员宅基地

文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

推荐文章

热门文章

相关标签