关于死锁的问题,有许多疑问。

2016-06-18 11:14:03
package com.dzr.thread;

class A {
public synchronized void foo(B b) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("打开A锁并进入程序....A锁被A中的 foo方法使用中.");
System.out.println("A中的foo方法要求B锁:...");
b.last();
}

public synchronized void last() {
System.out.println("A.last");
}
}

class B {
public synchronized void foo(A a) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("打开B锁并进入程序....B锁被B中的foo方法使用中..");
System.out.println("B中的foo方法要求A锁:...");
a.last();
}

public synchronized void last() {
System.out.println("B.last");
}
}

class DeadLock implements Runnable {
A a = new A();
B b = new B();

public void init() {
a.foo(b);
}

public void run() {
b.foo(a);
}
}

class C {

Object obj = new Object();

public void foo(D d) {

synchronized (obj) {

try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("打开C锁并进入程序....C锁被C中的 foo方法使用中.");
System.out.println("C中的foo方法要求D锁:...");
d.last();
}
}

public synchronized void last() {
System.out.println("C.last");
}
}

class D {

Object obj = new Object();

public void foo(C c) {

synchronized (obj) {

try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("打开D锁并进入程序....D锁被D中的 foo方法使用中.");
System.out.println("D中的foo方法要求C锁:...");
c.last();
}
}

public synchronized void last() {
System.out.println("D.last");
}
}

class DeadLock2 implements Runnable {
C c = new C();
D d = new D();

public void init() {
c.foo(d);
}

public void run() {
d.foo(c);
}
}

public class LockedTest {
public static void main(String[] args) {
DeadLock2 d = new DeadLock2();
new Thread(d).start();

d.init();

}
}


如上面这段代码, 其中AB类是教程里的关于死锁的案例 。这样锁住了是没有什么问题。但是我始终不明白为什么要进行一次这样的上锁行为,我通过变更,改称CD类的方式,就不再存在死锁的问题了 。
而且在这个问题中,我根本没有看到资源的抢占的问题,就象是自己进行一顿乱锁,本身 foo方法和 last方法并没有去使用相同的资源 ,却用同一把锁去锁住。
这个程序在需求上就不应该这么做,是不是得注意平时在锁文件的时候,也需要特别的注意,不同资源,需要用不同的锁锁住,这样才能防止本身毫无相关的资源调用,却造成了死锁的问题。
而相同的资源的使用,才是真正造成死锁的原因,因为你务必用同一把锁将其锁住,否则就不具备安全性。而如果在这种时候出现死锁的问题,则应该如何解决呢。
因为程序的设计和代码的本没有错,而只是在原理上导致了死锁的存在。

package com.ddd.thread;
/**
* 以哲学家问题为模型,AB两人需要吃饭 ,一共有两双筷子,A拿了筷子1
* B拿了筷子2, A等2 ,B等1 ,结果导致死锁。
*
* 同步区域,: 分别对筷子1和筷子2进行同步包装。
*
* 解决方案 ,1,如果A在一段时间没有拿到筷子第二个筷子,则放下第一个筷子。
* 2,如果两个筷子需要同时才能有效地进行工作, 为什么不将两个筷子放在一起,用一把锁锁住呢。
*
*
* */

/*
*
* 当人需要吃饭的时候,定义 eat方法,该方法需要两个筷子才能完成。
* 同步如何进行设置呢?
* 可以在Person类里面定义两个筷子的变量,
* */
class Kuaizi{
String name;
public Kuaizi(String name,boolean taken){
this.name = name;
this.taken =taken;
}
public boolean taken;
}
class Person{

Integer id;

int eat=0;//判断是否有两双筷子,如果有,则完成吃饭动作,否则,则不行。
public static Kuaizi left = new Kuaizi("left",false);
public static Kuaizi right = new Kuaizi("right",false);

public static Object oleft = new Object(); //定义锁
public static Object oright = new Object();

public Person(Integer id,int eat){
this.id = id;
this.eat =eat;
}
public boolean left(){//判断筷子是否被使用。那么筷子应该还有两个状态,被用。没被用。
return left.taken;
}
public boolean right(){
return right.taken;
}


public int useLeft(){
int i=0;
synchronized(oleft){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(left.taken==false)
{
left.taken=true;
i=1;
System.out.println(" "+this.id +"号使用左边的筷子");}
notify();
}
return i;
}

public int useRight(){
int i = 0;
synchronized(oright){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(right.taken==false)
{

right.taken = true;
i=1;
System.out.println(" "+this.id+"号使用右边的筷子");
notify();

}
}
return i;
}
/*
* 此时如何设置同步呢。如果要设置同步,需要在use方法里设置,但是筷子左右是分开的,所以需要分别设置一把锁 。
*
* */



public void eat(){

while(true){

if(right.taken == false)
{ eat+=useRight();

try {

Thread.currentThread().sleep(100);

} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if(left.taken == false)
eat+=useLeft();


try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(eat==2)
break;
if(eat==1)
System.out.println(this.id+"号只有一双筷子,没法吃饭!");
if(eat==0)
System.out.println(this.id+"号没有筷子,没法吃饭!");
}
left.taken = false;
right.taken = false;
System.out.println(this.id+"号吃到了饭 ");
}

}

/*
*
* 如何启动线程 。。。。定义个类,实现 接口,同时run里定义person吃饭即可。
*
* */

class EatClass implements Runnable{

@Override
public void run() {
Person person1 = new Person(100,0);
person1.eat();
}

}



public class SuoWenti {
public static void main(String[] args){

Thread t = new Thread(new EatClass());
t.start();

Person person2 = new Person(101,0);
person2.eat();

}
}



上面是我自己写的代码 。可是总是会报错 。    
Exception in thread "Thread-0" Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.dzr.thread.Person.useRight(SuoWenti.java:74)
at com.dzr.thread.Person.eat(SuoWenti.java:103)
at com.dzr.thread.EatClass.run(SuoWenti.java:149)
at java.lang.Thread.run(Unknown Source)
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.dzr.thread.Person.useRight(SuoWenti.java:74)
at com.dzr.thread.Person.eat(SuoWenti.java:103)
at com.dzr.thread.SuoWenti.main(SuoWenti.java:163)

为什么  waiting  处会抱错呢 。
...全文
68 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧