我知道while(true)放在调用同步方法sale()的地方程序运行是正确的,我想请大家帮我分析一下,当while(true)放在同步方法内,为什么只会启动第一个线程(Thread0),而其他线程不会启动。程序如下:(可将下面代码拷贝运行一下就会发现问题,问题是只有Thread0在运行,即只有一个窗口售票。)/*模拟售票窗口售票,每个线程是一个窗口,变量ticket是100张票共创建了4个线程,
 *即4个窗口卖100张票*/
class NewThread
{
public static void main(String [] args)
{
  TestThread tt=new TestThread(); //创建了4个线程,模拟4个售票窗口
  Thread t1=new Thread(tt);
  Thread t2=new Thread(tt);
  Thread t3=new Thread(tt);
  Thread t4=new Thread(tt);
  t1.start();
  t2.start();
  t3.start();
  t4.start();
}
}class TestThread implements Runnable
{
int ticket=100; //共同出售100张票
public void run()
{
sale();
}
public synchronized void sale() //定义同步方法
{
while(true)
{
if(ticket>0)
{
             try{Thread.sleep(1);}catch(Exception e1){}   //让线程睡眠
     System.out.println(Thread.currentThread().getName()+"is selling ticket"+ticket--);
}
}
}
}

解决方案 »

  1.   

    因为你while(true)没有终止条件,第一个线程调用的sale()方法一直不能结束,而且sale一直拥有tt的锁,其它线程得不到锁就一直等待
      

  2.   

    这个不需要同步吧?我调了一下,你看看是不是可以满足你的要求.
    package view;/**
     * <p>Title: testLog</p>
     *
     * <p>Description: </p>
     *
     * <p>Copyright: Copyright (c) 2006</p>
     *
     * <p>Company: </p>
     *
     * @author jy
     * @version 1.0
     */
    class NewThread {
        public static void main(String[] args) {
            TestThread tt = new TestThread(); //创建了4个线程,模拟4个售票窗口
            Thread t1 = new Thread(tt);
            Thread t2 = new Thread(tt);
            Thread t3 = new Thread(tt);
            Thread t4 = new Thread(tt);
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    class TestThread implements Runnable {
        int ticket = 100; //共同出售100张票
        boolean lock = false;
        public void run() {
            while (true) {
                if (ticket > 0) {
                    sale();
                  }
                  try {
                        Thread.sleep(1);
                        //Thread.yield();
                    } catch (Exception e1) {} //让线程睡眠        }    }    public void sale() { //定义同步方法        System.out.println(Thread.currentThread().getName() +
                               "is selling ticket" + ticket--);
       
        }
    }
      

  3.   

    谢谢tygker() 的回答,但是我认为问题应该不会出现在这里。
    我的程序是让线程不断切换,模拟窗口不停的售票,售卖到第1张时停止售票。第一个线程不需要结束,让线程sleep是模拟当ticket==1时(卖最后一张票时),此时运行的线程睡眠,其他三个线程sleep的地方(已经进入if(ticket>0))重新启动,就会打印出票号0,-1,-2;使用同步是避免它打印出0,-1,-2。而且线程调用sleep是会交出锁的,这么分析下来交出锁以后其他线程应该就会进入同步代码中啊。
      

  4.   

    谢谢xzjjy(青松)的回答。
    您回复的代码因为没使用线程同步可能会出现bug,sleep是为了模拟当cpu正好将线程切换时,程序可能出现的bug。您写的代码中sleep放到了sale()方法后面,所以等于没写,所以也就无法看到问题,如果您将sleep写道sale()方法前面,问题就会出现了。如:
    class NewThread {
        public static void main(String[] args) {
            TestThread tt = new TestThread(); //创建了4个线程,模拟4个售票窗口
            Thread t1 = new Thread(tt);
            Thread t2 = new Thread(tt);
            Thread t3 = new Thread(tt);
            Thread t4 = new Thread(tt);
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    class TestThread implements Runnable {
        int ticket = 100; //共同出售100张票
        boolean lock = false;
        public void run() {
            while (true) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(1);
                        //Thread.yield();
                        } catch (Exception e1) {} //让线程睡眠,模拟线程同步的安全性问题
                    sale();
                  }
            }    }    public void sale() { //定义同步方法        System.out.println(Thread.currentThread().getName() +
                               "is selling ticket" + ticket--);
       
        }
    }程序最后输出了0,-1,-2。
      

  5.   

    while(true)是为了让程序不停输出,直到if(ticker>0)时程序不再运行sale()方法,运行的是空循环,程序也就不会再输出。
      

  6.   

    Thread t1=new Thread(new TestThread());
      Thread t2=new Thread(new TestThread());
      Thread t3=new Thread(new TestThread());
      Thread t4=new Thread(new TestThread());
    这样试试。
      

  7.   

    代码这么写,应该能满足你的设计要求
    public class NewThread { /**
     * @param args
     */
    public static void main(String[] args) {
    TestThread tt = new TestThread();// 创建了4个线程,模拟4个售票窗口
    Thread t1 = new Thread(tt);
    Thread t2 = new Thread(tt);
    Thread t3 = new Thread(tt);
    Thread t4 = new Thread(tt);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    }}class TestThread implements Runnable {
    static int ticket = 100;// 共同出售100张票 public void run() {
    while (true) {
    sale();
    }
    } public synchronized void sale()// 定义同步方法
    {
    if (ticket > 0) {
    try {
    Thread.sleep(100);
    } catch (Exception e1) {
    } // 让线程睡眠
    System.out.println(Thread.currentThread().getName()
    + "is selling ticket" + ticket--);
    }
    }}
      

  8.   

    非常感谢fyuanfu(畅扬) 的回答。
    这样写我知道没问题,我就是想问问为什么这样写没问题,而我那样写就会只执行一个线程?两段代码应该差不多的啊,区别紧紧是将while(true)写在函数类和将while(true)写在函数外,为什么运行效果会不同咧?
      

  9.   

    谢谢zbo(大门)的回复
    如果按您的意思写的话,那4个线程都会创造自己的100张票,变成了4个窗口各卖各的100张票,因此程序也就失去了意义。
      

  10.   

    对不起,看漏了,
    zbo(大门)的代码中创建的4个线程使用的是4个TestThread类对象的锁,因此也达不到数据同步的效果,数据还是会输出0,-1,-2啊。
      

  11.   

    我觉得问题出在synchronized和sleep上,sleep只是交还cpu时间,但并不交还线程资源。而楼主又恰恰将sell声明为了synchronized,只允许一个线程占有,所以就会永远被第一个线程占领了。
    把楼主的代码sleep时间延长,也无济于事,说明问题不是sleep的时间太短,而是根本就不给其他线程机会,sleep再旧也没用:如果把楼主代码中的synchronized去掉就不会出现单独线程独占的问题了,但是又会出现楼主所说的负数问题。所以把while放在外面,区别就是每次只做-1的sell操作,而这个简单的元操作被synchronized起来,而不是整个的while都被synchronized。
      

  12.   

    其实按楼主的思路,应该用wait而不是sleep,但是wait又要涉及到notify,估计实现起来比较麻烦,可能要分别涉及4个线程类了
      

  13.   

    最近出差了,所以没时间来看,请大家见谅。
    是的,问题就出在sleep是不交出锁的(错怪了tygker兄),但while(true)写在函数外时,程序为何能正常运行呢?此时synchronized的函数sale()应该还是保留锁的,为什么其他线程可以调用此函数呢?