可重入锁详解(什么是可重入)

可重入锁详解(什么是可重入)可重入锁详解概述什么是“可重入”,可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。例如packagecom.test.reen;//演示可重入锁是什么意思,可重入,就是可以重复获取相同的锁,synchronized和ReentrantLock都是可重入的//可重入降低了编程复杂性publicclassWhatReentrant{ publicsta…

大家好,又见面了,我是你们的朋友全栈君。

可重入锁详解

概述

什么是 “可重入”,可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。例如

package com.test.reen;

// 演示可重入锁是什么意思,可重入,就是可以重复获取相同的锁,synchronized和ReentrantLock都是可重入的
// 可重入降低了编程复杂性
public class WhatReentrant { 
   
	public static void main(String[] args) { 
   
		new Thread(new Runnable() { 
   
			@Override
			public void run() { 
   
				synchronized (this) { 
   
					System.out.println("第1次获取锁,这个锁是:" + this);
					int index = 1;
					while (true) { 
   
						synchronized (this) { 
   
							System.out.println("第" + (++index) + "次获取锁,这个锁是:" + this);
						}
						if (index == 10) { 
   
							break;
						}
					}
				}
			}
		}).start();
	}
}
package com.test.reen;

import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

// 演示可重入锁是什么意思
public class WhatReentrant2 { 
   
	public static void main(String[] args) { 
   
		ReentrantLock lock = new ReentrantLock();
		
		new Thread(new Runnable() { 
   
			@Override
			public void run() { 
   
				try { 
   
					lock.lock();
					System.out.println("第1次获取锁,这个锁是:" + lock);

					int index = 1;
					while (true) { 
   
						try { 
   
							lock.lock();
							System.out.println("第" + (++index) + "次获取锁,这个锁是:" + lock);
							
							try { 
   
								Thread.sleep(new Random().nextInt(200));
							} catch (InterruptedException e) { 
   
								e.printStackTrace();
							}
							
							if (index == 10) { 
   
								break;
							}
						} finally { 
   
							lock.unlock();
						}

					}

				} finally { 
   
					lock.unlock();
				}
			}
		}).start();
	}
}

可以发现没发生死锁,可以多次获取相同的锁

可重入锁有

  • synchronized
  • ReentrantLock

使用ReentrantLock的注意点

ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样

以下代码演示,加锁和释放次数不一样导致的死锁

package com.test.reen;

import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

public class WhatReentrant3 { 
   
	public static void main(String[] args) { 
   
		ReentrantLock lock = new ReentrantLock();
		
		new Thread(new Runnable() { 
   
			@Override
			public void run() { 
   
				try { 
   
					lock.lock();
					System.out.println("第1次获取锁,这个锁是:" + lock);

					int index = 1;
					while (true) { 
   
						try { 
   
							lock.lock();
							System.out.println("第" + (++index) + "次获取锁,这个锁是:" + lock);
							
							try { 
   
								Thread.sleep(new Random().nextInt(200));
							} catch (InterruptedException e) { 
   
								e.printStackTrace();
							}
							
							if (index == 10) { 
   
								break;
							}
						} finally { 
   
// lock.unlock();// 这里故意注释,实现加锁次数和释放次数不一样
						}

					}

				} finally { 
   
					lock.unlock();
				}
			}
		}).start();
		
		
		new Thread(new Runnable() { 
   
			
			@Override
			public void run() { 
   
				try { 
   
					lock.lock();
					
					for (int i = 0; i < 20; i++) { 
   
						System.out.println("threadName:" + Thread.currentThread().getName());
						try { 
   
							Thread.sleep(new Random().nextInt(200));
						} catch (InterruptedException e) { 
   
							e.printStackTrace();
						}
					}
				} finally { 
   
					lock.unlock();
				}
			}
		}).start();
		
		
	}
}

由于加锁次数和释放次数不一样,第二个线程始终无法获取到锁,导致一直在等待。

稍微改一下,在外层的finally里头释放9次,让加锁和释放次数一样,就没问题了

try { 
   
	lock.lock();
	System.out.println("第1次获取锁,这个锁是:" + lock);

	int index = 1;
	while (true) { 
   
		try { 
   
			lock.lock();
			System.out.println("第" + (++index) + "次获取锁,这个锁是:" + lock);
			
			... 代码省略节省篇幅...
		} finally { 
   
// lock.unlock();// 这里故意注释,实现加锁次数和释放次数不一样
		}

	}

} finally { 
   
	lock.unlock();
	
	// 在外层的finally里头释放9次,让加锁和释放次数一样,就没问题了
	for (int i = 0; i < 9; i++) { 
   
		lock.unlock();
		
	}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/124905.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 看了很多人的面试经验,我也来一段:这段时间的几个面试

    看了很多人的面试经验,我也来一段:这段时间的几个面试
    泉州巴黎婚纱摄影
     
    店门口摆了个牌子,说招聘20名数码师,月薪2000-4000。又在网上也看到招聘启事,投了。
     
    投完,人才网收到个面试通知,不过简历状态竟然是未阅?通知人面试连简历都不看的?打了个电话过去,又给了我个电话,再打过去,电话里跟我说,我们这个职位啊,工作时间长工资低(6+*12+,<=800),你要有心理准备……KAO,牌子上不是写的2000-4000吗?到底打的啥鬼主意?
     
    过阵子在百度PS吧,看到有人发了一个贴

    2022年5月4日
    73
  • JAVA游戏开发-超炫酷贪吃蛇游戏源码及教程

    JAVA游戏开发-超炫酷贪吃蛇游戏源码及教程一.前言某日,看见隔壁家的小朋友在玩一款网络爆款贪吃蛇游戏,感觉很好玩。自己刚好正在学习JAVA编程,也想实现一个类似功能的游戏Demo练手,在网上查看了不少源码案例,全都是很古老的方块式贪吃蛇游戏案例,没有想要的实现,因此自己动手实现一个JAVA版的贪吃蛇游戏。我在这个Dome完成之后重写了这个游戏的Android版,并重新更名为《蛇王传说》。也欢迎大家下载试玩。游戏下载地址:https…

    2022年7月7日
    18
  • 编写java判断闰年_Java 判断闰年代码实例

    编写java判断闰年_Java 判断闰年代码实例importjava.util.Scanner;/*5.1判断闰年(时间:20分钟)5.1.1作业任务(1)由用户输入任意一个年份,能被4整除但不能被100整除,或者能被400整除,是闰年。(结果:输出闰年或平年)5.1.2任务要求(1)本题仅要求判断一个年份是否为闰年。5.1.3难点提示用?:运算符条件运算符是三目运算符,其格式为:表达式?语句1:语句2;其中表达式的值是布尔类型,…

    2022年7月17日
    8
  • JS设置定时器_js设置定时器

    JS设置定时器_js设置定时器JS定时器的一些特性和如何避免重复设置定时器概述和总结每个JS定时器产生时会被系统分配一个id,这个id是正整数,而且一个页面里面的定时器id不重复,我们能用一个变量接收这个id,但是如果重复执行一条接收创建语句,那么你只能接收到最新创建的定时器的id,之前创建的定时器的id会被覆盖,但是定时器数量在增加,这就会导致界面一些功能错乱,解决方法就是在重复按开始按钮时,如果已经有了一个定时器那么就不执行语句,我列出了错误代码和三种解决方法,可以解决定时器重复创建问题。ps:定时器id的配发是递增的,从1开

    2022年10月30日
    0
  • Java算法大全_java贪心算法几个经典例子

    Java算法大全_java贪心算法几个经典例子Java经典问题算法大全/*【程序1】题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?1.程序分析:兔子的规律为数列1,1,2,3,5,8,13,21….*/packagecn.com.flywater.FiftyAlgorthm;publicclassFirstR

    2022年10月17日
    0
  • Java学习代码合集

    Java学习代码合集其实我学习java最根本的原因是:我是一个挺关注外在的人,虽然是个程序员,所以我很喜欢写出那些带有漂亮的界面的程序,因为C总是控制台,我不是很喜欢,在这份java代码合集中,我会记录自己学习Java界面化编程的点点滴滴。更新:因为C/C++是我主要使用语言,所有后来写界面主要用Qt写了,但我java也会继续学的。我只是给想学界面gui的同志一个思路。可以参考这篇文章Qt5计算器的实现可能…

    2022年5月8日
    38

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号