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

智能推荐

hdu 1229 还是A+B(水)-程序员宅基地

文章浏览阅读122次。还是A+BTime Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24568Accepted Submission(s): 11729Problem Description读入两个小于10000的正整数A和B,计算A+B。...

http客户端Feign——日志配置_feign 日志设置-程序员宅基地

文章浏览阅读419次。HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息。FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。NONE:不记录任何日志信息,这是默认值。配置Feign日志有两种方式;方式二:java代码实现。注解中声明则代表某服务。方式一:配置文件方式。_feign 日志设置

[转载]将容器管理的持久性 Bean 用于面向服务的体系结构-程序员宅基地

文章浏览阅读155次。将容器管理的持久性 Bean 用于面向服务的体系结构本文将介绍如何使用 IBM WebSphere Process Server 对容器管理的持久性 (CMP) Bean的连接和持久性逻辑加以控制,使其可以存储在非关系数据库..._javax.ejb.objectnotfoundexception: no such entity!

基础java练习题(递归)_java 递归例题-程序员宅基地

文章浏览阅读1.5k次。基础java练习题一、递归实现跳台阶从第一级跳到第n级,有多少种跳法一次可跳一级,也可跳两级。还能跳三级import java.math.BigDecimal;import java.util.Scanner;public class Main{ public static void main(String[]args){ Scanner reader=new Scanner(System.in); while(reader.hasNext()){ _java 递归例题

面向对象程序设计(荣誉)实验一 String_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。-程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏6次。目录1.串应用- 计算一个串的最长的真前后缀题目描述输入输出样例输入样例输出题解2.字符串替换(string)题目描述输入输出样例输入样例输出题解3.可重叠子串 (Ver. I)题目描述输入输出样例输入样例输出题解4.字符串操作(string)题目描述输入输出样例输入样例输出题解1.串应用- 计算一个串的最长的真前后缀题目描述给定一个串,如ABCDAB,则ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA }ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。

算法设计与问题求解/西安交通大学本科课程MOOC/C_算法设计与问题求解西安交通大学-程序员宅基地

文章浏览阅读68次。西安交通大学/算法设计与问题求解/树与二叉树/MOOC_算法设计与问题求解西安交通大学

随便推点

[Vue warn]: Computed property “totalPrice“ was assigned to but it has no setter._computed property "totalprice" was assigned to but-程序员宅基地

文章浏览阅读1.6k次。问题:在Vue项目中出现如下错误提示:[Vue warn]: Computed property "totalPrice" was assigned to but it has no setter. (found in <Anonymous>)代码:<input v-model="totalPrice"/>原因:v-model命令,因Vue 的双向数据绑定原理 , 会自动操作 totalPrice, 对其进行set 操作而 totalPrice 作为计..._computed property "totalprice" was assigned to but it has no setter.

basic1003-我要通过!13行搞定:也许是全网最奇葩解法_basic 1003 case 1-程序员宅基地

文章浏览阅读60次。十分暴力而简洁的解决方式:读取P和T的位置并自动生成唯一正确答案,将题给测点与之对比,不一样就给我爬!_basic 1003 case 1

服务器浏览war文件,详解将Web项目War包部署到Tomcat服务器基本步骤-程序员宅基地

文章浏览阅读422次。原标题:详解将Web项目War包部署到Tomcat服务器基本步骤详解将Web项目War包部署到Tomcat服务器基本步骤1 War包War包一般是在进行Web开发时,通常是一个网站Project下的所有源码的集合,里面包含前台HTML/CSS/JS的代码,也包含Java的代码。当开发人员在自己的开发机器上调试所有代码并通过后,为了交给测试人员测试和未来进行产品发布,都需要将开发人员的源码打包成Wa..._/opt/bosssoft/war/medical-web.war/web-inf/web.xml of module medical-web.war.

python组成三位无重复数字_python组合无重复三位数的实例-程序员宅基地

文章浏览阅读3k次,点赞3次,收藏13次。# -*- coding: utf-8 -*-# 简述:这里有四个数字,分别是:1、2、3、4#提问:能组成多少个互不相同且无重复数字的三位数?各是多少?def f(n):list=[]count=0for i in range(1,n+1):for j in range(1, n+1):for k in range(1, n+1):if i!=j and j!=k and i!=k:list.a..._python求从0到9任意组合成三位数数字不能重复并输出

ElementUl中的el-table怎样吧0和1改变为男和女_elementui table 性别-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏2次。<el-table-column prop="studentSex" label="性别" :formatter="sex"></el-table-column>然后就在vue的methods中写方法就OK了methods: { sex(row,index){ if(row.studentSex == 1){ return '男'; }else{ return '女'; }..._elementui table 性别

java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下-程序员宅基地

文章浏览阅读1.1k次。java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下

推荐文章

热门文章

相关标签