当递归遇到synchronized
面试题:有一个synchronized方法,加入该方法发生递归调用,会导致线程死锁码? 解析:
所谓递归函数就是自调用函数,在函数体内直接或间接的调用自己,即函数的嵌套是函数本身。
递归方式有两种:直接递归和间接递归,直接递归就是在函数中出现调用函数本身。间接递归,指函数中调用了其他函数,而该其他函数又调用了本函数。
那什么时候使用递归呢?一般来说当你要在某段代码逻辑中使用循环迭代的时候但是迭代的次数在迭代之前无法知晓的情况下使用递归。打个比方你要在一个文件夹中查找某个文件,
而这个文件夹底下有N多子文件夹和文件,当你在不知道有多少层文件夹和文件的情况下你就得用到递归了。
递归的优点就是让代码显得很简洁,同时有些应用场景不得不使用递归比如前面说的找文件。递归是个好东西但是在某些时候也会给你带来一些麻烦。比如在多线程的环境下使用递归,
遇到了多线程那么就不得不面对同步的问题。而递归程序遇到同步的时候很容易出问题。多线程的递归就是指递归链中的某个方法由另外一个线程来操作,以下代码的意思都是这个意思即
调用recursive()和businessLogic()并非一个线程(如果是在一个线程中就不存在死锁问题,例如下面的recursive变成private就不存在问题。)
public class Test {
public void recursive(){
this.businessLogic();
}
public synchronized void businessLogic(){
System.out.println("处理业务逻辑");
System.out.println("保存到数据库");
this.recursive();
}
}
以上这段代码就是个能形成死锁的代码,事实上这个“synchronized”放在“businessLogic()”和“recursive()”都会形成死锁,并且是多线程的情况下就会锁住!
他的逻辑顺序是先执行recursive()方法然后接下来执行businessLogic()方法同时将businessLogic()方法锁住,接下来程序进入businessLogic()方法内部执行完
打印语句后开始执行recursive(),进入recursive()后准备执行businessLogic(),等等问题来了!之前执行的businessLogic()的锁还没有放开这次又执行到这里了,
当然是过不去的了,形成了死锁!从这个例子我们总结出来一个规律就是在递归的时候在递归链上面的方法上加锁肯定会出现死锁(所谓递归链就是指recursive()链向businessLogic(),
businessLogic()又链回recursive()),解决这个问题的方法就是避免在递归链上加锁,请看以下的例子
public class Test {
public void recursive(){
this.businessLogic();
}
public void businessLogic(){
System.out.println("处理业务逻辑");
this.saveToDB();
this.recursive();
}
public synchronized void saveToDB(){
System.out.println("保存到数据库");
}
}
saveToDB()不在这条递归链上面自然不会出现死锁,所以说在递归中加锁是件很危险的事情,实在逃不过要加锁就加在最小的粒度的程序代码上以减小死锁的概率。
当递归遇到synchronized的更多相关文章
- synchronized 是可重入锁吗?为什么?
什么是可重入锁? 关于什么是可重入锁,我们先来看一段维基百科的定义. 若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(re ...
- synchronized,ReentrantLock解决锁冲突,脏读的问题
最常见的秒杀系统,解决思路就是从前端.后台服务.数据库层层去掉负载,以达到平衡 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLo ...
- ConCurrent in Practice小记 (2)
Java-ConCurrent2.html :first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0 ...
- C、C++、Java、go的语法区别
详细C++.Java比较:http://www.cnblogs.com/stephen-liu74/archive/2011/07/27/2118660.html 一.C.C++的区别 在很大程度上, ...
- Java和C++的对比
事实上, Java 本来就是从 C++衍生出来的. C++和 Java 之间仍存在一些显著的差异.可以这样说,这些差异代表着技术的极大进步.一旦我们弄清楚了这些差异,就会理解为什么说 Java 是一种 ...
- 《Java编程思想第四版》附录 B 对比 C++和 Java
<Java编程思想第四版完整中文高清版.pdf>-笔记 附录 B 对比 C++和 Java “作为一名 C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且 Java 的语法无疑是 ...
- 【转】C++和Java比较
"作为一名C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且Java的语法无疑是非常熟悉的.事实上,Java本来就是从C++衍生出来的." 然而,C++和Java之间仍存 ...
- Differences or similarities between Java and C++
“作为一名C++程序员,我们早已掌握了面向对象Object-oriented Programming程序设计的基本概念,而且Java的语法无疑是非常熟悉的.事实上,Java本来就是从C++衍生出来的. ...
- JAVA编程思想中总结的与C++的区别
Java和C++都是面向对象语言.也就是说,它们都能够实现面向对象思想(封装,继乘,多态).而由于c++为了照顾大量的C语言使用者,而兼容了C,使得自身仅仅成为了带类的C语言,多多少少影响了其面向对象 ...
随机推荐
- 解决oh-my-zsh中git分支显示乱码问题
oh-my-zsh显示github分支时,如果当前文件夹不是git仓库,它就会显示乱码.倒腾了好几个小时终于弄清楚是oh-my-zsh中函数”git_prompt_info“的锅,然后又花了半个多小时 ...
- 心里想的VS嘴上说的
心里想的VS嘴上说的 背景:昨天开会,在招行总行那边,今天检讨下自己不会说话,真是太难了我! 一.昨日重现 现在回想起当时的场景觉得自己也真是搞笑,这都没死,太难了我.昨天下午在五楼开会,这也是我入职 ...
- MongoDB Day 1
创建数据库 db.createCollection("user"); 插入字段 //----insert------- db.user.insert({uid:1, user_co ...
- React 多副本问题
Element ref was specified as a string (MySider) but no owner was set. This could happen for one of t ...
- 整合-flowable-modeler,第一篇
BPMN流程想必大家都不陌生,经过这十几年的不断发展完善,在处理业务流程操作已经相当完善,我这里先不进行流程引擎的具体描述,单对集成流程设计器这块进行笔记,如有不对,跪求指出.
- Collectors.toMap不允许Null Value导致NPE
背景 线上某任务出现报警,报错日志如下: java.lang.NullPointerException: null at java.util.HashMap.merge(HashMap.java:12 ...
- vue路由传参的三种方式以及解决vue路由传参页面刷新参数丢失问题
最近项目中涉及到跨页面传参数和后台进行数据交互,看到需求之后第一反应就是用路由传参来解决:Vue中给我们提供了三种路由传参方式,下面我们一个一个的来看一下: 方法一:params传参: this.$r ...
- There’s More Than One Way To Do It!
There’s More Than One Way To Do It!
- 简析 Golang net/http 包
net/http 包涵盖了与 HTTP 请求发送和处理的相关代码.虽然包中定义了大量类型.函数,但最重要.最基础的概念只有两个:ServeMux 和 Handler. ServeMux 是 HTTP ...
- Unity进阶:行为树 02 夺旗战搭建场景,AI脚本,旗子拿起
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...