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语言多线程的不熟悉,看到这段代码是糊涂万分,希望能得到一份简单易懂的解释。

解决方案 »

  1.   

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

  2.   

    这么理解不对吧,执行wait()前,不可能切换线程,因为都是加锁的。
    你这程序我感觉不会死锁,挺正常一个程序,请其他高手鉴定
      

  3.   

    这位高手,你给的链接有个图,说线程有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.) 
      

  4.   

    说一下我的理解:首先这里没有死锁,只有死循环,是很简单的生产者-消费者模拟。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明白了吗?
      

  5.   

    这位高手,你给的链接有个图,说线程有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."

      

  6.   

    据我分析,不会有死锁的可能,wait()是会释放锁的。莫非楼主运行出现死锁?不可能吧
      

  7.   

    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();
         }
       } 
     }
      

  8.   

      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();  //等待
                                }
    还有这个,都是一样的效果。
      

  9.   

    我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,存钱后notify()取钱线程,但由于此时取钱线程不处于wait()状态,notify()无效。然后计算机继续执行之前未完成的wait(),之后取钱线程遍一睡不醒,导致存钱线程循环完毕后也陷入等待状态,死锁就形成了。
    当取钱完成之后,此时,存钱线程的断点在  wait()这里!
    直到,取钱线程调用了notify存钱现场才离开wait(),执行一个存钱的动作,而此时,取钱的线程的断点在 getMoney的wait 处。不会死锁如果你想死锁,要抢夺多个资源。