死锁线程探讨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中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能 ...
随机推荐
- 收集整理的非常有用的PHP函数
原文:收集整理的非常有用的PHP函数 项目中经常会需要一些让人头疼的函数,作为开发者应该整理一个自己的函数库,在需要之时复制过来即可.本文作者收集整理数十个PHP项目中常用的函数,保证能正常运行,你只 ...
- HDOJ 4416 Good Article Good sentence
题解转自:http://blog.csdn.net/dyx404514/article/details/8807440 2012杭州网络赛的一道题,后缀数组后缀自己主动机都行吧. 题目大意:给一个字符 ...
- 【MS SQL】把多个数据库合并为一个新的数据库
原文:[MS SQL]把多个数据库合并为一个新的数据库 因应工作要求,需要把两个数据库合并成一个库: 一开始使用"导入数据.导出数据和复制数据库"三个工具时,没有达到要的效果. 后 ...
- 33、Python.Unix和Linux系统管理指南.(美)基弗特
- 31、Thinking in Java
- 继承,is,as,多态
继承中的构造方法:1.创建子类对象时,一定会先创建父类对象2.如果调用的子类构造方法没有使用base,就会自动调用父类无参的构造方法, 如果父类没有无参的构造方法就会报错3.如果调用的子类构造方法 ...
- Android控件RecyclerView与ListView的异同
在我的一篇介绍Android新控件RecyclerView的博客(Android L新控件RecyclerView简介)中,一个读者留言说RecyclerView跟ListView之间好像没有什么不同 ...
- 使用 ArcGIS Online和APP进行监控操作和数据采集
主要介绍的App是Operations Dashboard for ArcGIS 和 Collector for ArcGIS,它们 提高了组织内日常操作的效率.精度和响应速度. 已经购买了 ArcG ...
- RequireJS 入门指南
RequireJS 入门指南 http://requirejs.org/ 简介如今最常用的JavaScript库之一是RequireJS.最近我参与的每个项目,都用到了RequireJS,或者是我向它 ...
- 冒泡排序最佳情况的时间复杂度,为什么是O(n)
冒泡排序最佳情况的时间复杂度,为什么是O(n) 我在许多书本上看到冒泡排序的最佳时间复杂度是O(n),即是在序列本来就是正序的情况下. 但我一直不明白这是怎么算出来的,因此通过阅读<算法导论-第 ...