JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计数值等于0时,锁释放。如果没有可重入锁的支持,在第二次 企图获得锁时将会进入死锁状态。

现实中,我们一般不会去手动实现锁,而是直接使用JDK或其他框架提供的锁,手动实现主要为了理解。

不可重入锁:

// 不可重入锁
class Lock{
// 是否占用
private boolean isLocked = false;
// 使用锁
public synchronized void lock() throws InterruptedException {
while(isLocked) {
wait();
}
isLocked = true;
}
// 释放锁
public synchronized void unlock(){
isLocked = false;
this.notify();
}
}

测试:

public class LockTest {

Lock lock = new Lock();

public void a() throws InterruptedException {

lock.lock();

b();

lock.unlock();

}

public void b() throws InterruptedException {

lock.lock();

// …业务代码

lock.unlock();

}

public static void main(String[] args) throws InterruptedException {
LockTest test = new LockTest();
test.a();
}

}

运行代码会发现出现死锁

可重入锁:

// 可重入锁
class ReLock{
// 是否占用
private boolean isLocked = false;
// 存储线程
private Thread lockedBy = null;
// 计数
private int holdCount = 0; // 使用锁
public synchronized void lock() throws InterruptedException {
Thread t = Thread.currentThread(); while(isLocked && lockedBy != t) {
this.wait();
}
isLocked = true;
lockedBy = t;
holdCount++;
} // 释放锁
public synchronized void unlock() {
if(Thread.currentThread() == lockedBy) {
holdCount--;
if(holdCount == 0) {
isLocked = false;
this.notify();
lockedBy = null;
}
}
} public int getHoldCount() {
return holdCount;
} }

测试:

public class LockTest02 {
ReLock lock = new ReLock();
public void a() throws InterruptedException {
lock.lock();
System.out.println(lock.getHoldCount());
b();
lock.unlock();
System.out.println(lock.getHoldCount());
}
public void b() throws InterruptedException {
lock.lock();
System.out.println(lock.getHoldCount());
// .....业务代码
lock.unlock();
System.out.println(lock.getHoldCount());
} public static void main(String[] args) throws InterruptedException {
LockTest02 test = new LockTest02();
test.a();
Thread.sleep(1000);
System.out.println(test.lock.getHoldCount());
}
}

运行代码:

可重入锁通过计数方式,没有出现死锁现象。

Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁的更多相关文章

  1. java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决

    0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...

  2. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

  3. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)

    一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...

  4. Java多线程——深入重入锁ReentrantLock

    简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...

  5. 【java多线程系列】java内存模型与指令重排序

    在多线程编程中,需要处理两个最核心的问题,线程之间如何通信及线程之间如何同步,线程之间通信指的是线程之间通过何种机制交换信息,同步指的是如何控制不同线程之间操作发生的相对顺序.很多读者可能会说这还不简 ...

  6. Java多线程:synchronized的可重入性

    从Java多线程:线程间通信之volatile与sychronized这篇文章中我们了解了synchronized的基本特性,知道了一旦有一个线程访问某个对象的synchronized修饰的方法或代码 ...

  7. “全栈2019”Java多线程第二十九章:可重入锁与不可重入锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. Java多线程系列——深入重入锁ReentrantLock

    简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...

  9. Java 多线程 重入锁

    作为关键字synchronized的替代品(或者说是增强版),重入锁是synchronized的功能扩展.在JDK 1.5的早期版本中,重入锁的性能远远好于synchronized,但从JDK 1.6 ...

随机推荐

  1. 添加windows开机自启动项

    windows系统下我们最常用的是禁用启动项,但如果程序不在自启动列表里面,如何添加程序启动呢. 其实也很简单,首先找到windows启动路径C:\Users\NL\AppData\Roaming\M ...

  2. C# Protobuf如何做到0分配内存的序列化

    题目很简单, 就是IMessage对象怎么变成Byte[] 答案1: msg.ToByteArray() 这肯定不符合我们的要求 答案2: using var memoryStream = new M ...

  3. SQL实战(三)

    一. 查找所有员工自入职以来的薪水涨幅情况,给出员工编号emp_noy以及其对应的薪水涨幅growth,并按照growth进行升序CREATE TABLE `employees` (`emp_no` ...

  4. RecyclerView 的简单使用

    自从 Android 5.0 之后,google 推出了一个 RecyclerView 控件,他是 support-v7 包中的新组件,是一个强大的滑动组件,与经典的 ListView 相比,同样拥有 ...

  5. while与until

    一.格式: while  条件测试 :do 循环体 done 二.条件测试 条件测试是指满足条件则会一直执行下去. 比如: let i =0 while i < 100;do echo $i i ...

  6. pyhton 信号量Semaphore和BoundedSemaphore

    Semaphore和BoundedSemaphore两个,用起来好像没啥区别 都是定义信号量 sem=threading.BoundedSemaphore(5) sem=threading.Semap ...

  7. 34.4 对象流 ObjectOutputStream ObjectInputStream

    * 对象操作流:可以用于读写任意类型的对象 * ObjectOutputStream * writeObject * ObjectOutputStream(OutputStream out) * Ob ...

  8. 29.3 ArrayList、List、LinkedList(链表)优缺点

    ArrayList.List特点:查询快.增删慢 链表特点:查询慢,增删快 案例 package day29_collection集合体系; import java.util.ArrayList; i ...

  9. Linux c++ vim环境搭建系列(0)——简介

    vim 学习 简介: 源码编译使用vim及其插件. 内容包含: vim的编译安装, llvm clang的编译安装, 插件youcompleteme的编译安装使用, 以及vim其他插件的使用. 搭建环 ...

  10. ArrayBlockingQueue和LinkedBlockingQueue的使用

    ArrayBlockingQueue和LinkedBlockingQueue的使用 博客分类: java.util.concurrent   BlockingQueue接口定义了一种阻塞的FIFO q ...