当递归遇到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语言,多多少少影响了其面向对象 ...
随机推荐
- C#使用LitJson解析Json数据
//接受MQ服务器返回的值 private void jieshou(string zhiling, string can1, string can2, string can3, string can ...
- 武林 HDU - 1107
题目链接:https://vjudge.net/problem/HDU-1107 注意:题目中只有两个不同门派的人在同一个地方才能对决,其他情况都不能对决. 还有,这步的有效的攻击只有走到下一步之后才 ...
- 1、Java小白之路前言
大二一年准备好好学习Java,养成一个良好的习惯写博客,但是由于各种各样的原因,并没有坚持下来.而正好又赶上大三结束,去实习,发现自己的基础还是有些薄弱,所以决定,重新走上这条Java小白之路. 时隔 ...
- cogs 1254. 最难的任务 Dijkstra + 重边处理
1254. 最难的任务 ★ 输入文件:hardest.in 输出文件:hardest.out 简单对比时间限制:1 s 内存限制:128 MB [题目描述] 这个真的很难.算出 123 ...
- 算法与数据结构基础 - 折半查找(Binary Search)
Binary Search基础 应用于已排序的数据查找其中特定值,是折半查找最常的应用场景.相比线性查找(Linear Search),其时间复杂度减少到O(lgn).算法基本框架如下: //704. ...
- (十二)c#Winform自定义控件-分页控件
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- centos7 环境下安装nginx--Linux
一.安装前需要的编译环境准备 1.安装make yum install -y gcc automake autoconf libtool make 2.安装gcc.gcc-c++ yum instal ...
- mssql server master 数据库还原
今天想试一下master数据库还原,在进入单用户模式的时候,在命令行输入sqlserver.exe -c -f -m结果显示 'sqlserver.exe' 不是内部或外部命令,也不是可运行的程序或批 ...
- 手撕ThreadPoolExecutor线程池源码
这篇文章对ThreadPoolExecutor创建的线程池如何操作线程的生命周期通过源码的方式进行详细解析.通过对execute方法.addWorker方法.Worker类.runWorker方法.g ...
- ansible之变量
一.常用系统变量 1. loop #表示循环,去读循环体里的变量固定使用{{item}},item是个字典对象item.key=value,例如如下playbook内容: --- - name: ...