/**
 * 本程序是模拟火车票售票
 * 先存票再取票
 */
package Thread.App11_2;/**
 * @WriteBy 
 * @E-mail [email protected]
 * @date 2012-7-27
 * @time 下午5:18:03
 */class Tickets {
private int size; // 设置票的总数
boolean available = false; // 标识当前是否有票可售 true代表有票可售
boolean stop = false; // 标识票是否售完 true表示票已售完
int num; public Tickets(int size) {
this.size = size;
} // 存票
public synchronized void put() {
if (available)
try {
wait();
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("存入第" + (++num) + "张票!");
available = true;
notify();
} // 售票
public synchronized void sell() {
if (!available)
try {
wait();
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("售出第" + num + "张票!");
if (num == size)
stop = true;
available = false;
notify();
}}// 存票机
class Producer extends Thread {
Tickets tickets = null; public Producer(Tickets tickets) {
this.tickets = tickets;
} public void run() {
while (tickets.stop == false)
tickets.put();
}}// 售票机
class Consumer extends Thread {
Tickets tickets = null; public Consumer(Tickets tickets) {
this.tickets = tickets;
} public void run() {
while (tickets.stop == false)
tickets.sell();
}
}public class APP11_2 { /**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
Tickets tickets = new Tickets(10);
new Producer(tickets).start();
new Consumer(tickets).start(); }}我运行的时候出现存入第1张票!
售出第1张票!
存入第2张票!
售出第2张票!
存入第3张票!
售出第3张票!
存入第4张票!
售出第4张票!
存入第5张票!
售出第5张票!
存入第6张票!
售出第6张票!
存入第7张票!
售出第7张票!
存入第8张票!
售出第8张票!
存入第9张票!
售出第9张票!
存入第10张票!
售出第10张票!
存入第11张票!
而调试的时候就不会出现最后的“存入第11张票 这是为什么

解决方案 »

  1.   

    个人浅见:
    运行时,程序连续运行,没有等待. 在存第10张票时,存入完,线程马上又判断stop==false为真,(此时,消费线程还没执行完,stop就是false. 生产线程又进入等待),等消费线程结束后,生产线程接着生产出第11个,再次循环判断stop==false,为假了,结束了。
    而你调试用单步执行,生产完第10个后,线程没有马上判断 stop==false,而是等消费线程把第10个消费后,把stop赋值true后,再次执行生产线程,判断stop==false为假了,线程结束了。 
      

  2.   

    1. stop 变量没有同步
    2. 多线程间通信时,尽量使用 循环判断+notifyAll.而不是单次判断+ notify
      

  3.   

    这句话我不理解  为什么stop变量没有同步啊 总共就两个线程,第一个wait一下 第二个再notify一下 不就同步了嘛
      

  4.   

    有办法不让线程再存入第11张票.
    1 在生产线程里把运行tickets.put()的条件改一下。
    class Producer extends Thread {
        Tickets tickets = null;    public Producer(Tickets tickets) {
            this.tickets = tickets;
        }    public void run() {
            //while (tickets.stop == false)
              while(tickets.stop==false&&tickets.num<10)  //num=10则不再出票了。
                tickets.put();
        }}
    2  在put()方法里判断num如果大于10,则不输出了。
       public synchronized void put() {
            if (available)
                try {
                    wait();
                } catch (Exception e) {
                    // TODO: handle exception
                }
    ++num;                                                   //改的地方
    if(num<=10)                                              //num大于10,不输出了。
    {
    System.out.println("存入第" + num + "张票!");
    available = true;
             notify();
    }
        }
      

  5.   

    不解释为什么:class Tickets {
    private int size; // 设置票的总数
    boolean available = false; // 标识当前是否有票可售 true代表有票可售
    boolean stop = false; // 标识票是否售完 true表示票已售完
    int num; public Tickets(int size) {
    this.size = size;
    } // 存票
    public synchronized void put() {
    if (available){
    try {
    wait();
    } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
    }

    }else{
    System.out.println("存入第" + (++num) + "张票!");
    available = true;
    notify();
    }
    } // 售票
    public synchronized void sell() {
    if (!available){
    try {
    wait();
    } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
    }
    }else{
    System.out.println("售出第" + num + "张票!");
    if (num == size)
    stop = true;
    available = false;
    notify();
    }
    }}// 存票机
    class Producer extends Thread {
    Tickets tickets = null; public Producer(Tickets tickets) {
    this.tickets = tickets;
    } public void run() {
    while (tickets.stop == false)
    tickets.put();
    }}// 售票机
    class Consumer extends Thread {
    Tickets tickets = null; public Consumer(Tickets tickets) {
    this.tickets = tickets;
    } public void run() {
    while (tickets.stop == false)
    tickets.sell();
    }
    }public class APP11_2 { /**
     * @param args
     */
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    Tickets tickets = new Tickets(10);
    new Consumer(tickets).start();
    new Producer(tickets).start(); }}
    楼主看看行不?
      

  6.   

    不让它输出第11张票我也会啊 但是我改用stop方法了就不行了,我想知道为什么啊
      

  7.   

    我觉得运行时消费线程运行到notify();时,生产线程会运行下去,调试的时候时间会比较长,结果就没运行
    建议改成public synchronized void put() {
            while (available)   // 这里if最好改成while
                try {
                    wait();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            System.out.println("存入第" + (++num) + "张票!");
            available = true;
            notify();
        }
    // 售票
        public synchronized void sell() {
            if (!available)   // 同理这里if也最好改成while
                try {
                    wait();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            System.out.println("售出第" + num + "张票!");
            if (num == size)
                stop = true;
            available = false;
            notify();
        }
    if最好改成while,因为楼主是要靠available控制线程运行
      

  8.   

    没有用吧,我试了一下,问题不在这里,改成while也没用
      

  9.   

    改成while也是没用的  
      

  10.   

    <a href="http://www.baidu.com">百度一下,你就知道!</a>
      

  11.   

        改成while 解决不了楼主这个问题。while结束后,put()或sell()方法后面的语句还要执行。
        
        7楼的办法可以,在if后面的语句和else后面的语句是分两次执行的。就是说执行if后面的语句,结束后,sell()或者put() 就结束了,run()方法继续判断条件tickets.stop == false,决定是否继续调用sell()或者put()方法。
        等到生产线程的put()方法生产了10个后,消费线程还有执行完sell()方法,所以生产线程又进入了put()方法,但因为availble为true,所以进入了wait().
        当消费线程sell()输出后,stop为true, notify()通知生产线程继续运行,此时if()结束。退出put()方法。线程再次判断tickets.stop == false时,已经为假,while()结束了。所以不再输出第11张票了。
      

  12.   

    现在有两个线程,一个produce,一个consumer,当available==false,即没有票时,sell等待,put执行,put完事后唤醒sell,说来取票。注意在sell票还没取走时,put可能又开始了存票,但不好意思他就只能等待。等到sell完事后唤醒put,说你可以干活了。
    前面几位说的很清楚了,输出11的问题在于第10张票还没取走,stop依旧false,这时produce的put方法开始了,但available为true,put就在等待,待到sell结束后,唤醒了put方法,从wait()继续往下执行。
    if(){
    wait();
    }
    A();//A存入第十一张票
    if(){
    wait();
    }else{
    A();
    }
    一个A执行,一个A不执行,这两段代码的区别应该很明白了吧
      

  13.   

    if(){
    wait();
    }
    A();//存第十一张票if(){
    wait
    }else{
    A();
    }楼上的几位说的很清楚了。代码1 存票执行,代码2 不执行,这个楼主应该明白了吧