当前位置:编程学习 > JAVA >>

请教JAVA多线程中死锁的问题。

package syn4;
/**
 * 测试类
 */
public class TestAccount {
         public static void main(String[] args) {
                   Accout a = new Accout();
                   StudentThread s = new StudentThread(a);
                   GenearchThread g = new GenearchThread(a);
         }
}
package syn4;
/**
 * 模拟学生线程
 */
public class StudentThread extends Thread {
         Accout a;
         public StudentThread(Accout a){
                   this.a = a;
                   start();
         }
         public void run(){
                   try{
                            while(true){
                                     Thread.sleep(2000);
                                     a.getMoney();  //取钱
                            }
                   }catch(Exception e){}
         }
}
package syn4;
/**
 * 家长线程
 */
public class GenearchThread extends Thread {
         Accout a;
         public GenearchThread(Accout a){
                   this.a = a;
                   start();
         }
         public void run(){
                   try{
                            while(true){
                                     Thread.sleep(12000);
                                     a.saveMoney();  //存钱
                            }
                   }catch(Exception e){}
         }
}
package syn4;
/**
 * 银行账户
 */
public class Accout {
         int money = 0;
         /**
          * 取钱
          * 如果账户没钱则等待,否则取出所有钱提醒存钱
          */
         public synchronized void getMoney(){
                   System.out.println("准备取钱!");
                   try{
                            if(money == 0){
                                     wait();  //等待
                            }
                            //取所有钱
                            System.out.println("剩余:" + money);
                            money -= 50;
                            //提醒存钱
                            notify();
                   }catch(Exception e){}                 
         }
         
         /**
          * 存钱
          * 如果有钱则等待,否则存入200提醒取钱
          */
         public synchronized void saveMoney(){
                   System.out.println("准备存钱!");
                   try{
                            if(money != 0){
                                     wait();  //等待
                            }
                            //取所有钱
                            money = 200;
                            System.out.println("存入:" + money);
                            //提醒存钱
                            notify();
                   }catch(Exception e){}                 
         }
}


一,这是老师给的关于消费者生产者问题的代码。
二,我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,存钱后notify()取钱线程,但由于此时取钱线程不处于wait()状态,notify()无效。然后计算机继续执行之前未完成的wait(),之后取钱线程遍一睡不醒,导致存钱线程循环完毕后也陷入等待状态,死锁就形成了。
三,因为对JAVA语言多线程的不熟悉,看到这段代码是糊涂万分,希望能得到一份简单易懂的解释。。。。 --------------------编程问答-------------------- "我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,"
    上面这句话, 消费者在synchronized void getMoney()这个同步方法里,不执行wait()语句的话,生产者因为得不到同步对象的锁,会在锁池池子里等待,是无法执行的。
参考一下:
http://blog.csdn.net/jiafu1115/article/details/6804386
    --------------------编程问答--------------------
引用 楼主 luang4322551 的回复:
我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程

这么理解不对吧,执行wait()前,不可能切换线程,因为都是加锁的。
你这程序我感觉不会死锁,挺正常一个程序,请其他高手鉴定 --------------------编程问答--------------------
引用 1 楼 nmyangym 的回复:
"我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,"
    上面这句话, 消费者在synchronized void getMoney()这个同步方法里,不执行wait()语句的话,生产者因为得不到同步对象的锁,会在锁池池子里等待,是无法执行的。
参考一下:
http://blog.csdn.net/jiafu1115/article/details/6804386
   

这位高手,你给的链接有个图,说线程有7种状态,但是《Java核心技术》这本书中说Java线程只有6种状态,以下是原文:
Threads can be in one of six states:
•New
• Runnable
• Blocked
•Waiting
• Timed waiting
•Terminated

Once you invoke the start method, the thread is in the runnable state. A runnable 
thread may or may not actually be running. It is up to the operating system to give 
the thread time to run. (The Java specification does not call this a separate state, 
though. A running thread is still in the runnable state.) 
--------------------编程问答-------------------- 要是硬要说会出现死锁,我觉得那有可能是没有吧存钱或者取钱线程唤醒,而是唤醒了别的线程。那么就可能出现死锁了. --------------------编程问答-------------------- 说一下我的理解:

首先这里没有死锁,只有死循环,是很简单的生产者-消费者模拟。

wait()表示让出CPU使用权,让CPU执行其他thread,同时释放对象锁。

Account对象,分别有两个synchronized的方法,表示调用此方法时,account对象被锁定。

生产者,和消费者的构造方法里,调用了start()启动线程。

在测试类里, new了两个对象,其实只启动了2个thread(不算main线程)

1)当消费者第一次取钱时,money==0,此线程wait(),释放account对象

2)生产者存钱,存完一笔后,调用notify()唤醒其他线程,唤醒消费者。此时有2个线程同时使用CPU,但是money!=0时,生产者wait()

3)消费者享有CPU使用权,每次去50,每次调notify()唤醒生产者线程,但money!=0时,生产者继续wait()
...

LZ明白了吗? --------------------编程问答--------------------
引用 3 楼 andycpp 的回复:
Quote: 引用 1 楼 nmyangym 的回复:

"我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,"
    上面这句话, 消费者在synchronized void getMoney()这个同步方法里,不执行wait()语句的话,生产者因为得不到同步对象的锁,会在锁池池子里等待,是无法执行的。
参考一下:
http://blog.csdn.net/jiafu1115/article/details/6804386
   

这位高手,你给的链接有个图,说线程有7种状态,但是《Java核心技术》这本书中说Java线程只有6种状态,以下是原文:
Threads can be in one of six states:
•New
• Runnable
• Blocked
•Waiting
• Timed waiting
•Terminated

Once you invoke the start method, the thread is in the runnable state. A runnable 
thread may or may not actually be running. It is up to the operating system to give 
the thread time to run. (The Java specification does not call this a separate state, 
though. A running thread is still in the runnable state.) 


我给的例子中,runnable 状态分开了。runnable and running.
"Once you invoke the start method, the thread is in the runnable state. A runnable 
thread may or may not actually be running."
--------------------编程问答-------------------- 据我分析,不会有死锁的可能,wait()是会释放锁的。莫非楼主运行出现死锁?不可能吧 --------------------编程问答-------------------- 绝对不会有死锁!! --------------------编程问答-------------------- 1 wait 的虚假唤醒是存在的,建议放到循环中执行。
2 以下是简单jdk上面建议的生产者消费者的例子,使用ReentrantLock和condition来写。

class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }
--------------------编程问答--------------------   public synchronized void getMoney(){
                   System.out.println("准备取钱!");
                   try{
                            if(money == 0){
                                     wait();  //等待
                            }
   看这一些代码,如果money为0的话你就要等待了,等待过程中是占有锁的,另一个线程是取不到这个锁的,而此时线程也是没有办法执行notify操作的,就死锁了。
  public synchronized void saveMoney(){
                   System.out.println("准备存钱!");
                   try{
                            if(money != 0){
                                     wait();  //等待
                            }
还有这个,都是一样的效果。 --------------------编程问答-------------------- 不会产生死锁。。。 --------------------编程问答-------------------- 我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,存钱后notify()取钱线程,但由于此时取钱线程不处于wait()状态,notify()无效。然后计算机继续执行之前未完成的wait(),之后取钱线程遍一睡不醒,导致存钱线程循环完毕后也陷入等待状态,死锁就形成了。


当取钱完成之后,此时,存钱线程的断点在  wait()这里!
直到,取钱线程调用了notify

存钱现场才离开wait(),执行一个存钱的动作,而此时,取钱的线程的断点在 getMoney的wait 处。

不会死锁

如果你想死锁,

要抢夺多个资源。 
补充:Java ,  Java SE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,