死锁线程探讨Java中的死锁现象
题记:写这篇博客要主是加深自己对死锁线程的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。
今天搞了一下Java的死锁机制,感到自己还是不怎么懂,所以就从一些简略的源代码中琢磨:我先尝试写了一个很简略的死锁代码:思绪是线程A取得B的锁但还没有取得C的锁,所以在等待取得C的锁,还线程A1取得了C的锁但没有取得B锁所以就在等待B的锁,所以就造成了相互等待,程序陷入死锁状态……
死锁程序:
public class DeadLock{
public static void main(String[] args) {
final Object a=new Object(),b=new Object();
Thread t1 = new Thread(new A(a,b));
Thread t2 = new Thread(new A1(a,b));
t1.start();
t2.start();
}
}
class A implements Runnable{
private Object B,C;
public A(Object B,Object C){
this.B=B;
this.C=C;
}
@Override
public void run() {
synchronized(B){ //取得B的锁
System.out.println("A线程取得B的锁等待C的锁");
synchronized(C){
System.out.println("A线程取得B的锁也取得了C的锁");
}
}
}
}
class A1 implements Runnable{
private Object B,C;
public A1(Object B,Object C){
this.B=B;
this.C=C;
}
@Override
public void run() {
synchronized(C){ //取得B的锁
System.out.println("A1线程取得B的锁等待C的锁");
synchronized(B){
System.out.println("A1线程取得B的锁也取得了C的锁");
}
}
}
}
线程A和A1处于相互等待对方释放锁,就这样一直对峙着,这段代码要避免死锁有两个方法:
方法一:在启动两个线程之间加入sleep()方法,只要休眠充足长的时光,让线程A先执行完再启动线程A1就可以避免死锁
t1.start();
try{
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e){}
t2.start();
方法二,采用join()方法
t1.start();t1.join();
t2.start();t2.join();
在死锁案例中,最经典的课本案例应该是哲学家吃饭问题(我自己这样称谓),讲的是有5个哲学家,每个都做同样的事,一天的时光都在思考、吃饭的循环中渡过,饭桌上一共只有5只筷子,一个人必须要有两只筷子才能够吃饭,所以哲学家就必须向身旁的人拿筷子,当一同拿时就会发生死锁,假设哲学家都是先拿左边的筷子再拿右边的筷子,哲学家围成一圈,这样每个人左边和右边都有一只筷子。
例程:
package thread.test;
import java.util.concurrent.TimeUnit;
public class DeadLock{
public static void main(String[] args) {
try{
//一共有5双筷子5个哲学家
Chopsticks[] chops=new Chopsticks[5];
Philosopher[] peps=new Philosopher[5];
for(int i=0;i<5;i++){
chops[i] = new Chopsticks(i);
}
for(int i=0;i<5;i++){
peps[i] = new Philosopher(chops[i],chops[(i+1)/5],i);
}
//启动五个线程
for(int i=0;i<5;i++){
new Thread(peps[i]).start();
}
如果只看到太阳的黑点,那你的生活将缺少温暖;如果你只看到月亮的阴影,那么你的生命历程将难以找到光明;如果你总是发现朋友的缺点,你么你的人生旅程将难以找到知音;同样,如果你总希望自己完美无缺,假设你的这一愿望真的能如愿以偿,那么你最大的缺点就是没有缺点。
TimeUnit.SECONDS.sleep(4);//延时充足长的时光视察哲学家的动态
System.exit(0); //程序必须退出!
}catch(InterruptedException e){
System.out.println("interrupted");
}
}
}
class Chopsticks {
private final int id;
public Chopsticks(int i){
id=i;
}
private boolean OnTake=false;
synchronized public void take()throws InterruptedException{
while(OnTake)
wait();
OnTake=true;
}
synchronized public void drop(){
OnTake=false;
notifyAll();
}
public String toString(){
return "chopstcks:"+id;
}
}
class Philosopher implements Runnable{
private Chopsticks left;
private Chopsticks right;
private final int id;
public Philosopher(Chopsticks l,Chopsticks r,int id){
left = l; //左边的筷子
right = r; //右边的筷子
this.id=id;
}
//模拟哲学家思考所占有的时光
private void pause()throws InterruptedException{
TimeUnit.MILLISECONDS.sleep(400);
}
@Override
public void run() {
try{
while(!Thread.interrupted()){
System.out.println(this+"在思考");
pause();
System.out.println(this+"拿筷子吃饭");
left.take(); //先拿左边的筷子
pause();
right.take(); //这顿饭永久也吃不完
System.out.println(this+"吃完放下筷子");
left.drop();
right.drop();
}
}catch(InterruptedException e){
e.printStackTrace();
}
}
public String toString(){
return " 哲学家"+id;
}
}
这段程序按照我们预想的结果是每个哲学家都在思考,然后顺次吃完饭后放下筷子让另外的人吃,因为每个人需要两根筷子,总有人会没有筷子!但实际情况是:每个人都先拿起左边的筷子,然后等待某一个人把右边的筷子给他,但每个人都是这样想的,所以每个人都拿不到对方的筷子,所以这顿饭永久也吃不完!程序陷入了死锁。话说到这里,我们就有须要晓得满足死锁的四个须要条件:1:互斥条件:资源每次只能被一个线程使用。如前面的“线程同步代码段”。 2:请求与坚持条件:一个线程因请求资源而阻塞时,对已取得的资源坚持不放。 3:不褫夺条件:进程已取得的资源,在未使用完之前,无法强行褫夺。 4:循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件只要一个不满足就不会陷入死锁,一般我们容易破坏第四个条件,只要让其中一个哲学家先拿右边的筷子程序就不会陷入死锁!
修改后不会陷入死锁的程序:
for(int i=0;i<4;i++){
peps[i] = new Philosopher(chops[i],chops[i+1],i);
}
//最后一个哲学家先拿右边的筷子,即chops[0]筷子
peps[4] = new Philosopher(chops[0],chops[4],4);
看完这篇文章就留下了一个我从书上摘抄上去的练习:修改程序,使切当哲学家用完筷子以后,把筷子放在一个筷笼中,当哲学家要就餐时就从筷笼里取出下两根可用的筷子。这消除了死锁的可能吗?你能通过仅仅增加可用的筷子数目就从新引入死锁吗?如果要索要谜底,就请留下邮箱地址,我发谜底给你,或许你的谜底比我的好得多!交流是一种快乐!
文章结束给大家分享下程序员的一些笑话语录:
火车
一个年轻的程序员和一个项目经理登上了一列在山里行驶的火车,他们发现 列车上几乎都坐满了,只有两个在一起的空位,这个空位的对面是一个老奶 奶和一个年轻漂亮的姑娘。两个上前坐了下来。程序员和那个姑娘他们比较 暧昧地相互看对方。这时,火车进入山洞,车厢里一片漆黑。此时,只听见 一个亲嘴的声音,随后就听到一个响亮的巴掌声。很快火车出了山洞,他们 四个人都不说话。
那个老奶奶在喃喃道, “这个年轻小伙怎么这么无礼, 不过我很高兴我的孙女 扇了一个巴掌”。
项目经理在想,“没想到这个程序员居然这么大胆,敢去亲那姑娘,只可惜那 姑娘打错了人,居然给打了我。”
漂亮的姑娘想,“他亲了我真好,希望我的祖母没有打疼他”。
程序员坐在那里露出了笑容, “生活真好啊。 这一辈子能有几次机会可以在亲 一个美女的同时打项目经理一巴掌啊”
---------------------------------
原创文章 By
死锁和线程
---------------------------------
死锁线程探讨Java中的死锁现象的更多相关文章
- java中的死锁现象
死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. java 死锁产生的四个必要条件: 1.互斥使用,即当资源被一个线 ...
- 编写 Java 程序时, 如何在 Java 中创建死锁并修复它?
经典但核心Java面试问题之一.如果你没有参与过多线程并发 Java 应用程序的编码,你可能会失败.
- 线程:Java中wait、notify、notifyAll使用详解
基础知识 首先我们需要知道,这几个都是Object对象的方法.换言之,Java中所有的对象都有这些方法. public final native void notify(); public final ...
- 深入探讨Java中的异常与错误处理
Java中的异常处理机制已经比较成熟,我们的Java程序到处充满了异常的可能,如果对这些异常不做预先的处理,那么将来程序崩溃就无从调试,很难找到异常所在的位置.本文将探讨一下Java中异常与错误的处理 ...
- Java中的死锁问题
死锁问题: 例如有两个线程, 线程1与线程2. 线程1在执行的过程中, 要锁定对象1, 2才能完成整个操作, 首先锁定对象1, 再锁定对象2. 线程2在执行的过程中, 要锁定对象2, 1才能完成整个操 ...
- 转自CSDN-详述 Java 中的别名现象
在任何编程语言中,赋值操作都是最常见的操作之一,Java 自然也不例外.赋值时,使用赋值操作符=,它的意思是:“将等号右边的值(右值),复制给左边的值(左值)”.右值可以是任何常数.变量或者表达式(只 ...
- 探讨 java中 接口和对象的关系
接口是对象么?接口可以有对象么?这个问题要跟类比对着,或许更好理解;类是对象的模版.接口不是类,所以:接口肯定不是对象的模版.那接口跟对象有什么样的关系?还是得从类入手;因为类实现了接口,所以可以说, ...
- Java中的主线程
目录 概览 主线程 怎么来控制主线程 主线程和main()函数的关系 主线程中的死锁(单个线程) 概览 前段时间有同事提到了主线程这个名词,但当时我们说的主线程是指Java Web程序中每一个请求进来 ...
- Java多线程中的死锁问题
Java程序基本都要涉及到多线程,而在多线程环境中不可避免的要遇到线程死锁的问题.Java不像数据库那么能够检测到死锁,然后进行处理,Java中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能 ...
随机推荐
- navigator,JS检测浏览器插件
最早由Netscape Navigator 2.0引入的navigator对象,现在已经成为识别客户端浏览器的事实标准.虽然其它浏览器也通过其它方式提供了相同或相似的信息(例如,IE中的window. ...
- Shell的学习就从重装系统开始吧
小标题:与Fedora的爱恨情仇 干巴巴的shell学习实在枯燥,看来学习姿势还是要从实践入手 起因:传说中的不作死就不会死,昨晚偶遇一本PDF,讲glade编辑界面的,以下就被吸引了,跟着讲解搞出个 ...
- openwrt的GPIO控制
为什么有些GPIO可以在/sys/class/gpio中控制,而有些不行呢? 先来看一看普通不需要C程序而是使用脚本的控制方法(Linux普遍适用): First step is making GPI ...
- ajax提交表单 验证
function submitKH(mobileInputId,nameInputId) { var mobileInputSelector ='#'+ mobileInputId; var pass ...
- Extjs 组件继承 模板说明(同GridPanel案件)
1. 重写initComponent()方法,并在该方法在调用父类的initComponent()方法. 如:subclass.superclass.initComponent.call(this) ...
- Machine Learning - XI. Machine Learning System Design机器学习系统的设计(Week 6)
http://blog.csdn.net/pipisorry/article/details/44119187 机器学习Machine Learning - Andrew NG courses学习笔记 ...
- c#自带压缩类实现数据库表导出到CSV压缩文件
c#自带压缩类实现数据库表导出到CSV压缩文件的方法 在导出大量CSV数据的时候,常常体积较大,采用C#自带的压缩类,可以方便的实现该功能,并且压缩比例很高,该方法在我的开源工具DataPie中已经经 ...
- 应用CSS的page-break-after属性 实现WEB页面强制分页打印
虽然dedecms.com向大家介绍了很多CSS属性的相关知识,但有些非常冷门的属性还是有所欠缺.在B/S程序中,对打印页面的控制,CSS相对比较弱,例如: 自动分页, 就基本没啥实际用途.我们通常需 ...
- MobileProbe的使用
MobileProbe是CNZZ移动这块统计的一个产品,目前似乎分成了基础版和专业版.下载地址为: http://m.cnzz.com/?a=main&m=download&f=inf ...
- Introducing ASP.NET vNext and MVC 6
[译]Introducing ASP.NET vNext and MVC 6 原文:http://www.infoq.com/news/2014/05/ASP.NET-vNext?utm_source ...