再造管程的理由

synchronized导致死锁问题,提出了一个破坏不可抢占条件方案,但是这个方案 synchronized 没有办法解决。原因是 synchronized 申请资源的时候,如果申请不到,线程直接进入阻塞状态了,而线程进入阻塞状态,啥都干不了,也释放不了线程已经占有的资源。但我们希望的是:

对于“不可抢占”这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。

如果我们重新设计一把互斥锁去解决这个问题,那该怎么设计呢?我觉得有三种方案。

1、能够响应中断。synchronized 的问题是,持有锁 A 后,如果尝试获取锁 B 失败,那么线程就进入阻塞状态,一旦发生死锁,就没有任何机会来唤醒阻塞的线程。但如果阻塞状态的线程能够响应中断信号,也就是说当我们给阻塞的线程发送中断信号的时候,能够唤醒它,那它就有机会释放曾经持有的锁 A。这样就破坏了不可抢占条件了。
2、支持超时。如果线程在一段时间之内没有获取到锁,不是进入阻塞状态,而是返回一个错误,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。
3、非阻塞地获取锁。如果尝试获取锁失败,并不进入阻塞状态,而是直接返回,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。
这三种方案可以全面弥补 synchronized 的问题。到这里相信你应该也能理解了,这三个方案就是“重复造轮子”的主要原因,体现在 API 上,就是 Lock 接口的三个方法。详情如下:

// 支持中断的 API
void lockInterruptibly() throws InterruptedException;
// 支持超时的 API
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 支持非阻塞获取锁的 API
boolean tryLock();

如何保证可见性

class X {private final Lock rtl = new ReentrantLock();int value;public void addOne() {// 获取锁rtl.lock();  try {value+=1;} finally {// 保证锁能释放rtl.unlock();}}
}

ReentrantLock,内部持有一个 volatile 的成员变量 state,获取锁的时候,会读写 state 的值;解锁的时候,也会读写 state 的值(简化后的代码如下面所示)。也就是说,在执行 value+=1 之前,程序先读写了一次 volatile 变量 state,在执行 value+=1 之后,又读写了一次 volatile 变量 state。根据相关的 Happens-Before 规则:
1、顺序性规则:对于线程 T1,value+=1 Happens-Before 释放锁的操作 unlock();
2、volatile 变量规则:由于 state = 1 会先读取 state,所以线程 T1 的 unlock() 操作 Happens-Before 线程 T2 的 lock() 操作;
3、传递性规则:线程 T1 的 value+=1 Happens-Before 线程 T2 的 lock() 操作。

class SampleLock {volatile int state;// 加锁lock() {// 省略代码无数state = 1;}// 解锁unlock() {// 省略代码无数state = 0;}
}

什么是可重入锁

所谓可重入锁,顾名思义,指的是线程可以重复获取同一把锁

除了可重入锁,可能你还听说过可重入函数,可重入函数怎么理解呢?指的是线程可以重复调用?显然不是,所谓可重入函数,指的是多个线程可以同时调用该函数,每个线程都能得到正确结果;同时在一个线程内支持线程切换,无论被切换多少次,结果都是正确的。多线程可以同时执行,还支持线程切换,这意味着什么呢?线程安全啊。所以,可重入函数是线程安全的。

class X {private final Lock rtl = new ReentrantLock();int value;public int get() {// 获取锁rtl.lock();         try {return value;} finally {// 保证锁能释放rtl.unlock();}}public void addOne() {// 获取锁rtl.lock();  try {value = 1 + get(); } finally {// 保证锁能释放rtl.unlock();}}
}

公平锁与非公平锁

在使用 ReentrantLock 的时候,你会发现 ReentrantLock 这个类有两个构造函数,一个是无参构造函数,一个是传入 fair 参数的构造函数。fair 参数代表的是锁的公平策略,如果传入 true 就表示需要构造一个公平锁,反之则表示要构造一个非公平锁

// 无参构造函数:默认非公平锁
public ReentrantLock() {sync = new NonfairSync();
}
// 根据公平策略参数创建锁
public ReentrantLock(boolean fair){sync = fair ? new FairSync() : new NonfairSync();
}

锁都对应着一个等待队列,如果一个线程没有获得锁,就会进入等待队列,当有线程释放锁的时候,就需要从等待队列中唤醒一个等待的线程。如果是公平锁,唤醒的策略就是谁等待的时间长,就唤醒谁,很公平;如果是非公平锁,则不提供这个公平保证,有可能等待时间短的线程反而先被唤醒。

Java并发编程实战~Lock相关推荐

  1. java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...

    [Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...

  2. Java并发编程实战_不愧是领军人物!这种等级的“Java并发编程宝典”谁能撰写?...

    前言 大家都知道并发编程技术就是在同一个处理器上同时的去处理多个任务,充分的利用到处理器的每个核心,最大化的发挥处理器的峰值性能,这样就可以避免我们因为性能而产生的一些问题. 大厂的核心负载肯定是非常 ...

  3. 视频教程-Java并发编程实战-Java

    Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...

  4. 【极客时间】《Java并发编程实战》学习笔记

    目录: 开篇词 | 你为什么需要学习并发编程? 内容来源:开篇词 | 你为什么需要学习并发编程?-极客时间 例如,Java 里 synchronized.wait()/notify() 相关的知识很琐 ...

  5. Java并发编程实战之互斥锁

    文章目录 Java并发编程实战之互斥锁 如何解决原子性问题? 锁模型 Java synchronized 关键字 Java synchronized 关键字 只能解决原子性问题? 如何正确使用Java ...

  6. 《Java 并发编程实战》--读书笔记

    Java 并发编程实战 注: 极客时间<Java 并发编程实战>–读书笔记 GitHub:https://github.com/ByrsH/Reading-notes/blob/maste ...

  7. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  8. aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  9. Java并发编程实战————恢复中断

    中断是一种协作机制,一个线程不能强制其他线程停止正在执行的操作而去执行其他操作. 什么是中断状态? 线程类有一个描述自身是否被中断了的boolean类型的状态,可以通过调用 .isInterrupte ...

最新文章

  1. java公网对讲_【对讲机的那点事】选择公网对讲机你必须要知道使用的网络信号!...
  2. 分拣外观残缺的机器人_中国鞋业高峰论坛大咖云集,国辰机器人解读“鞋业智造”...
  3. Boost Asio总结(7)class strand
  4. wget: unable to resolve host address “mirrors.163.com” 的解决办法
  5. .NET Core 如何禁止.resx文件自动生成Designer.cs
  6. destoon 自定义session丢失
  7. 瑞芯微RK3128-微信Airkiss2.0配网功能调试及实现
  8. SQL 查询所有表名、字段名、类型、长度、存储过程、视图
  9. 2017年西安邮电大学第十二届数学建模竞赛B题论文
  10. Java接入腾讯云短信接口
  11. Conflux DAO 社区技术委员会成立 助力生态繁荣发展
  12. HDU 1814 Two_Sat
  13. “如果Java受到一两个大型供应商的控制,则可能会遭受挫折”
  14. JavaScript智能填写续写版(QQ邮箱地址栏简化版)
  15. 请求网站响应的文本带有乱码,原来是Content-encoding惹的祸,一文带你搞懂`Content-encoding`、`Accept-Encoding`
  16. 关于Vue开发即时聊天类功能的经验分享(其实并不复杂)
  17. 神探夏洛克第一季/全集Sherlock1迅雷下载
  18. 2010浙大报录比及分数
  19. 从一到无穷大 #4 Lossy compression
  20. OpenWrt固件编译

热门文章

  1. 阿里java架构师面试128题含答案:分布式架构+Dubbo+多线程+Redis
  2. 【Tensorflow】小白入门实战基础篇(上)
  3. 最短路径——迪杰斯特拉算法——图的数据结构
  4. json数组格式问题
  5. 潭州Java中级班(day_05)
  6. Flash Media Server 4.5下载
  7. cut命令详解(转)
  8. SharePoint创建web application的时候报错
  9. opacity:0.99;
  10. php: eclipse 编辑 php