死锁线程探讨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中的死锁问题,只能通过程序员自己写代码时避免引入死锁的可能 ...
随机推荐
- log4e插件的安装和使用
1.首先下载log4e小工具.放入myeclipse10安装文件夹D:\Program Files (x86)\myEclipse10\MyEclipse Blue Edition 10\dropin ...
- Oralce 导出脚本命令,定时执行
原文:Oralce 导出脚本命令,定时执行 @echo off @echo ================================================ @echo window ...
- MongoDB的C#驱动
MongoDB的C#驱动基本使用 MongoDB的官方C#驱动可以通过这个链接得到.链接提供了.msi和.zip两种方式获取驱动dll文件. 通过这篇文章来介绍C#驱动的基本数据库连接,增删改查操作. ...
- sql点滴42—mysql中的时间转换
原文:sql点滴42-mysql中的时间转换 UNIX时间戳转换为日期用函数: FROM_UNIXTIME() select FROM_UNIXTIME(1156219870); 日期转换为UNIX时 ...
- Android SDK Web SDK 接口测试总结
什么是SDK SDK就是一个程序,提供一些方法,调用这些方法,可以实现一些功能.如:调用银行提供的SDK,可以实现在线支付的功能. 目前主要接手的SDK有js SDK 和android SDK.JS ...
- 负载均衡DNS和反向代理优缺点
负载均衡 (Load Balancing) 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡(又 ...
- 基于Jcrop的图片上传裁剪加预览
最近自己没事的时候研究了下图片上传,发现之前写的是有bug的,这里自己重新写了一个! 1.页面结构 <!DOCTYPE html> <html lang="en" ...
- Objective C多态
面向对象的封装的三个基本特征是.继承和多态. 包是一组简单的数据结构和定义相关的操作在上面的其合并成一个类,继承1种亲子关系,子类能够拥有父类定的成员变量.属性以及方法. 多态就是指父类中定义的成员变 ...
- 【DateTime格式大全
】
DateTime dt = DateTime.Now;// Label1.Text = dt.ToString();//2005-11-5 13:21:25// Label2.Text = ...
- 如何防范CC攻击
服务器如何防范CC攻击CC攻击是DDOS(分布式拒绝服务)的一种,相比其它的DDOS攻击CC似乎更有技术含量一些.这种攻击你见不到虚假IP,见不到特别大的异常流量,但造成服务器无法进行正常连接,听说一 ...