是什么

synchronized关键词功能一致,让线程保持同步。synchronized是基于Java语法上的实现,而ReentrantLock是基于API实现,操作上相对灵活。JDK1.7 之后 两者的性能上不分秋色。ReentrantLock实现了Lock接口,我们来看看那Lock几个主要接口定义:

/**
当前线程尝试获取独占锁,如果发现锁已被其他线程占用将被挂起。
**/
void lock();/**
同void lock() 方法类似,只不过该方法能够被线程中断。
**/
void lockInterruptibly() throws InterruptedException;/**
当前线程调用该方法会尝试获取锁,如果获取到返回true,反之返回false,并不会阻塞该线程。
**/
boolean tryLock();
/**
同boolean tryLock()方法类似。也是尝试获取锁,在拿不到锁时会等待一定时间,等待时可以被中断。超时之后还未拿到锁返回false.
**/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;/**释放锁。
**/
void unlock();/**返回一个与lock实例绑定的Condition,通过调用Condition#await()方法,可以释放当前线程持有的锁并阻塞挂起。
**/
Condition newCondition();

Condition的作用主要应用于多线程的协同,下面看看Condition 接口的一些主要定义:

/**对于获取锁的线程,调用此方法后会阻塞直到其他线程唤醒或者线程被中断
**/
void await() throws InterruptedException;/**
相比较await()而言,它不响应中断。
**/
void awaitUninterruptibly();
/**
唤醒因调用同一个condition实例的await() 方法 而阻塞挂起的线程
**/
void signal();/**唤醒所有阻塞的线程
**/
void signalAll();

怎么用

ReentrantLock锁的基本使用

需求:有20个用户(线程)同时去抢购剩余的10张火车票,必须保证数据不出现混乱。具体实现如下:

TicketMachine

/*** 取票机*/
public class TicketMachine {Lock lock = new ReentrantLock();/*** 票数量*/private Integer ticketNum = 10;/*** 购买*/public void buying() {try {// 1.lock.lock();if (ticketNum > 0) {System.out.println(Thread.currentThread().getName() + "购买了第" + ticketNum + "张票");ticketNum--;} else {System.out.println("已购买完,抢不到了.");}} catch (Exception e) {e.printStackTrace();} finally {// 2.lock.unlock();}}
}

运行方法

 TicketMachine ticketMachine = new TicketMachine();for (Integer i = 0; i < 20; i++) {new Thread(() -> {ticketMachine.buying();}, "同学" + (i + 1)).start();}

运行结果

同学1购买了第10张票
同学4购买了第9张票
同学2购买了第8张票
同学3购买了第7张票
同学5购买了第6张票
同学6购买了第5张票
同学7购买了第4张票
同学8购买了第3张票
同学9购买了第2张票
同学10购买了第1张票
已购买完,抢不到了.
已购买完,抢不到了.
已购买完,抢不到了.
已购买完,抢不到了.
已购买完,抢不到了.
已购买完,抢不到了.

上面有几处我们着重的说一下 。代码(1)处调用lock() 方法获取锁保证同一时刻只能有一个线程对变量ticketNum(票数)进行操作,不会造成脏数据的问题。代码(2)处将unlock()方法放置finally块中 确保代码执行完毕后锁能进行释放,不造成死锁。

针对此案例我们提出几个疑问

  • 若没有调用lock()方法,直接调用 unLock() 方法会出现问题么?
  • 若多次调用lock()方法,仅调用一次 unLock() 方法会出现问题么?

问题一:若无调用lock() 方法,直接执行unLock() 方法将会抛出IllegalMonitorStateException。
问题二: 会导致其他线程获取不到锁。

Lock结合Condition 的使用

需求:10个线程每次以10增量值对变量sum进行求和运算,当任何一个线程发现求和运算得出的结果等于100,将唤醒另一个线程将结果输出。

具体实现如下:

/*** Lock 和 Condition 配合使用案例*/
public class LockConditionDemo {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();/*** 总和*/private Integer sum = 0;/*** 计算和** @param count*/public void calcSum(Integer count) {try {lock.lock();sum += count;//4.if (sum == 100) {condition.signal();System.out.println("sum 已等于 100 ,唤醒线程...");}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}/*** 显示总和*/public void show() {try {lock.lock();System.out.println("线程【"+Thread.currentThread().getName()+"】"+"等待输出sum和");//2.condition.await();System.out.println("线程【"+Thread.currentThread().getName()+"】"+"得出 sum = " + sum);} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}

运行方法:

    public static void main(String[] args) {LockConditionDemo t = new LockConditionDemo();//1.Thread thread = new Thread(() -> {t.show();}, "获取求和线程");thread.start();//3.for (Integer i = 0; i < 10; i++) {new Thread(() -> t.calcSum(10), "线程" + i).start();}}

输出结果:

线程【获取求和线程】等待输出sum和
sum 已等于 100 ,唤醒线程...
线程【获取求和线程】得出 sum = 100

从代码(1) 处,我们可以看出启动了一个 获取求和线程,代码(2) 处,调用了condition.await()方法,将该线程阻塞挂起,等待其他线程唤醒,代码(3) 处启动了20个 对变量sum求和的线程,紧接着代码(4)处对sum的值进行判断,如果等于100将调用 condition.signal(),唤醒因调用同一个condition实例的await() 方法 而阻塞挂起的线程。


清山绿水始于尘,博学多识贵于勤。
我有酒,你有故事吗?
微信公众号:「Java锦囊」。
欢迎一起谈天说地,聊Java。


书写技术文章是一个循序渐进的过程,所以我不能保证每句话、每行代码都是对的,但至少能保证不复制、不粘贴,每篇文章都是自己对技术的认识、细心斟酌总结出来的。乔布斯说:我们在这个星球上的时间都很短,很少有机会去做几件真正伟大的事情,同时要做得好,我必须要趁我还年轻的时候完成这些事。
其实我想说的是,我是一枚程序员,我只想在有限的时间内尽可能去沉淀我这一生中所能沉淀下来的东西

ReentrantLock入门级相关推荐

  1. 机器阅读理解(MRC)零基础入门级综述(一)

    目录 机器阅读理解(MRC)零基础入门级综述(一) 一.机器阅读理解(MRC)是什么? 1. 含义 2. 分类 3. 机器阅读理解(Reading Comprehension) vs. 问答(Ques ...

  2. ReentrantLock+线程池+同步+线程锁

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...

  3. UML类图新手入门级介绍

    UML类图新手入门级介绍 看了大话设计模式,觉得很生动形象,比较适合于我这种初学者理解面向对象,所以就记录了一下. 举一个简单的例子,来看这样一副图,其中就包括了UML类图中的基本图示法. 首先,看动 ...

  4. ReentrantLock与synchronized

    1.ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的 ...

  5. 【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍

    游戏开发笔记二十七 Direct3D 11入门级知识介绍 作者:毛星云    邮箱: happylifemxy@163.com    期待着与志同道合的朋友们相互交流 上一节里我们介绍了在迈入Dire ...

  6. ReentrantLock实现原理分析

    ReentrantLock主要利用CAS+CLH队列来实现.它支持公平锁和非公平锁,两者的实现类似. CAS:Compare and Swap,比较并交换.CAS有3个操作数:内存值V.预期值A.要修 ...

  7. JUC AQS ReentrantLock源码分析

    Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchronized还 ...

  8. 通俗易懂的ReentrantLock,不懂你来砍我

    前言 自己开的坑,跪着也要填完,欢迎来到Java并发编程系列第五篇ReentrantLock,文章风格依然是图文并茂,通俗易懂,本文带读者们深入理解ReentrantLock设计思想. 认识下Reen ...

  9. 这篇 ReentrantLock 看不懂,加我我给你发红包

    来自:Java建设者 回答一个问题 在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 J ...

最新文章

  1. C 语言中赋值表达式的返回的逻辑值
  2. 使用matplotlib做动态排名图
  3. 地图投影系列介绍(二)----地理坐标系
  4. 关于filter用户授权的例子
  5. fscanf、fprintf的返回值
  6. UIView中的坐标转换
  7. iOS使用得图SDK开发VR播放器
  8. 杜比专为旧版本Android,Android O专用杜比音效miui10已成功
  9. 战德臣计算机导论第5讲,地方高校“计算机导论”算法思维培养的教学设计
  10. 《华为研发》阅读 - 11 (中研部组织结构)
  11. 小米获取屏幕高度不准确-小米获取屏幕高度的兼容方案
  12. 2017年江苏省高等数学竞赛试题解答手稿
  13. Springboot整合邮件发送(163邮箱为例)
  14. 做SEO优化应该掌握哪些基础知识
  15. android系统可以识别NTFS格式吗,安卓手机支持ntfs格式的储存卡吗
  16. matlab晶体能带,matlab平面波展开法的二维光子晶体能带研究+程序
  17. 163企业邮箱申请,163企业邮箱注册方法
  18. 用计算机解题前 需要将解题方法,算法及其表示方法
  19. ICC Scenario Difinition(什么是Scenario?)
  20. 全国计算机竞赛能保送清华北大吗,通过参加学科竞赛获得保送清华北大的机会很少,还有必要参加吗?...

热门文章

  1. AI技术再升级:2022年最流行的10大人工智能技术
  2. 服务器统一计算系统,思科统一计算系统(UCS)
  3. webservice小解
  4. 虚拟仪器总线技术的发展和应用
  5. Amazon Studios预订获奖喜剧《了不起的麦瑟尔夫人》第四季
  6. Zookeeper简单介绍
  7. 索尼电视linux系统版本,索尼X9500H智能液晶4K电视加入最新安卓9.0操作系统
  8. SpringBoot 多数据源
  9. Cisco/Ruijie/H3C/华为 AAA认证配置
  10. 中国搜索领域起战火:百度与360交锋