ReentrantLock实现Lock接口,所以先看下Lock接口:

public interface Lock {
    // 获得锁
    void lock();
    // 获得锁
    void unlock();
    // lock非阻塞版本,成功返回true
    boolean tryLock();
    // 添加尝试时间,时间到返回false
    boolean tryLock(long time, TimeUnit unit)
    // 返回一个监视器对象
    Condition newCondition();
}

再来看ReentrantLock的常用API:

public class ReentrantLock implements Lock,Serializable {
    // 构造器,可以实现公平锁
    public ReentrantLock()
    public ReentrantLock(boolean fair)
    public void lock()
    // 可中断锁
    public void lockInterruptibly()
    // 可轮询的锁获取,有返回值。获取成功返回true;获取失败,返回false,线程不会阻塞、
    public boolean tryLock()
    public boolean tryLock(long timeout, TimeUnit unit)
    // 返回一个监视器对象
    Condition newCondition();
} 

ReentrantLock的使用方法分为这么几块:

1. 可重入锁的实现;

2. 公平锁与非公平锁;

3. 配合Condition实现的选择性通知, condition实现阻塞队列,这两个可以视为同一块;

4. tryLock的实现;

5.生产者消费者模式实现,如果用Condition实现这个模式,其实跟实现阻塞队列是类似的;

同样也可以单纯使用阻塞队列实现生产者消费者模式;

可重入锁的实现

可以再次获取自己的内部锁,即:一个线程获取某对象锁,在没有释放此对象锁的同时,可以再次获得此锁;

锁释放请务必在finally中进行

public class ReentrantLockTest {
    private static final Lock lock = new ReentrantLock();

    public static void test1() {
        lock.lock();
        try {
            System.out.println("已进入test_1");
            test2();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void test2() {
        lock.lock();
        try {
            System.out.println("已进入test_2");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

公平锁与非公平锁

只要在构造器中传入true,实现方面没什么好说的;

  • 非公平锁下的后来线程可以插队,减少了一定的线程上下文切换

  • 公平锁下后来的线程必须排队等待锁的释放,多进行了一步判断,线程挂起的几率比较高,所以效率略低

    满足FIFO(先进先出队列)

非公平锁虽然效率高,但是有可能出现线程饿死的情况,比如客户端一直无法获得服务,所以,服务器一般用公平锁实现;

配合Condition实现的选择性通知

这个可以跟实现阻塞队列一起说了,感觉代码层面,基本一致;

public class MyBlockingQueue<T> {
    private int limit;
    private final Lock lock = new ReentrantLock();
    private final Condition Full = lock.newCondition();
    private final Condition Empty = lock.newCondition();
    private List<T> queue = new LinkedList<>();

    public MyBlockingQueue(int limit) {
        this.limit = limit;
    }

    public void enqueue(T item) throws InterruptedException {
        lock.lock();
        try {
            // 队列满
            while (queue.size() == limit) {
                Full.await();
            }
            queue.add(item);
            Empty.signal();
        } finally {
            lock.unlock();
        }
    }

    public T dequeue(T item) throws InterruptedException {
        lock.lock();
        try {
            // 队列空
            while (queue.size() == 0) {
                Empty.await();// 将当前线程阻塞在Empty监视器下
            }
            Full.signal(); // 叫醒Full监视器下阻塞的线程
            return queue.remove(0);
        } finally {
            lock.unlock();
        }
    }
}

tryLock的实现

tryLock方法可以无参,可以传入等待时间;

public class MytryLock {

    private static final Lock lock = new ReentrantLock();
    // 由于是否获得锁不确定,所以设置标志位判断
    private static boolean isLocked = false;

    public static void test() {
        try {
            if (lock.tryLock(1000, TimeUnit.MILLISECONDS)) {
                // trylock返回true,即拿到锁
                isLocked = true;
                System.out.println(Thread.currentThread().getName() + "拿到锁!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                /**
                 * 没拿到锁,可以让线程继续做别的事
                 * 不会阻塞
                 */
                System.out.println(Thread.currentThread().getName() + "没拿到锁!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (isLocked == true)
                lock.unlock();
        }
    }
}

生产者消费者模式实现

同condition实现阻塞队列;

queue就是生产者的仓库对象;

enqueue就是生产;

dequeue就是消费;

【JUC】3.ReentrantLock的更多相关文章

  1. 【1】【JUC】JDK1.8源码分析之ReentrantLock

    概要: ReentrantLock类内部总共存在Sync.NonfairSync.FairSync三个类,NonfairSync与FairSync类继承自Sync类,Sync类继承自AbstractQ ...

  2. 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)

    一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...

  3. 【1】【JUC】JDK1.8源码分析之ArrayBlockingQueue,LinkedBlockingQueue

    概要: ArrayBlockingQueue的内部是通过一个可重入锁ReentrantLock和两个Condition条件对象来实现阻塞 注意这两个Condition即ReentrantLock的Co ...

  4. 【JUC】阻塞队列&生产者和消费者

    阻塞队列 线程1往阻塞队列添加元素[生产者] 线程2从阻塞队列取出元素[消费者] 当队列空时,获取元素的操作会被阻塞 当队列满时,添加元素的操作会被阻塞 阻塞队列的优势:在多线程领域,发生阻塞时,线程 ...

  5. 【JUC】JDK1.8源码分析之ReentrantLock(三)

    一.前言 在分析了AbstractQueuedSynchronier源码后,接着分析ReentrantLock源码,其实在AbstractQueuedSynchronizer的分析中,已经提到过Ree ...

  6. 【JUC】4.Synchronized与ReentrantLock对比

    与synchronized相同,ReentrantLock也是一种互斥锁: synchronized与ReentrantLock的对比: 都是可重入锁 可以再次获取自己的内部锁,即:一个线程获取某对象 ...

  7. 【1】【JUC】Condition和生产者消费者模型

    本篇文章将介绍Condition的实现原理和基本使用方法,基本过程如下: 1.Condition提供了await()方法将当前线程阻塞,并提供signal()方法支持另外一个线程将已经阻塞的线程唤醒. ...

  8. 【JUC】synchronizated和lock的区别&新lock的优势

    原始构成 synchronized是关键字,属于JVM层面 javap -c 的结果显示 synchronized是可重入锁 11:是正常退出 17:是异常退出[保证不产生死锁和底层故障] Lock是 ...

  9. 【JUC】JUC锁框架综述

    一.前言 在分析完了集合框架后,很有必要接着分析java并发包下面的源码,JUC(java.util.concurrent)源码也是我们学习Java迈进一步的重要过程.我们分为几个模块进行分析,首先是 ...

随机推荐

  1. vue-admin-template 切换回中文

    使用vue-admin-template开发项目,使用的是element-ui的控件,但这个框架走的是国际化,是英文版,好吧!快速切换为中文版: 找到main.js 第七行: 替换为: import ...

  2. (3)PyCharm中Flask工程逆向生成数据库表

    一.创建数据库 在mysql数据库中创建名为"movie"的数据库. 二.安装SQLAlchemy 三.安装PyMySQL 四.创建数据模型 在app/models.py中编写数据 ...

  3. C语言 sscanf函数补充

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h&g ...

  4. Java 使用ZkClient操作Zookeeper

    目录 ZkClient介绍 导入jar包依赖 简单使用样例 ZkClient介绍 因为Zookeeper API比较复杂,使用并不方便,所以出现了ZkClient,ZkClient对Zookeeper ...

  5. LeetCode,3. 无重复字符的最长子串

    看了各位大神的,真是难堪,尤其是各种c++动不动就击败99%...我用python,换了三次算法,改了十几次bug,才击败5%....贴出来纪念下吧. 题目如下: 给定一个字符串,请你找出其中不含有重 ...

  6. 阿里云k8s部署zookeeper集群

    1. 阿里云k8s创建有状态应用 StatefulSet ,  选择使用模板创建 可以创建自定义模板 apiVersion: apps/v1 kind: StatefulSet metadata: c ...

  7. 可扩展标记语言XML之二:XML语言格式规范、文档组成

    大家好,小乐又来了,好久不见!这次接着上次可扩展标记语言XML之一:XML概念,作用,示例,继续讲述XML. 一.格式良好的 xml 1.语法规范: 1).必须有 XML 文档声明: <?xml ...

  8. Weave跨主机实现docker互通,固定ip及dns使用介绍

    一.weave介绍Weave是由weaveworks公司开发的解决Docker跨主机网络的解决方案,现在就采用它来实现Docker多宿主机互联的目的,它能够创建一个虚拟网络,用于连接部署在多台主机上的 ...

  9. Ubuntu19.04 Help

    Ubuntu Dock 为应用程序启用最小化操作,立即生效. $ gsettings set org.gnome.shell.extensions.dash-to-dock click-action ...

  10. 20190715《Python网络数据采集》第 1 章

    <Python网络数据采集>7月8号-7月10号,这三天将该书精读一遍,脑海中有了一个爬虫大体框架后,对于后续学习将更加有全局感. 此前,曾试验看视频学习,但是一个视频基本2小时,全部拿下 ...