一个线程不会 运行 直到另一个线程结束

One thread does not run till the other one is ended

我正在做一个简单的生产者消费者问题。服务员是生产者,厨师是消费者。我已经实现它,以便 Chef 线程等待,直到 Waiter 通知它队列中有传入订单。

public class Main {

    public static void main(String args[]) {
        final Queue<Integer> sharedQ = new LinkedList<Integer>();
        Thread waiter = new Waiter(sharedQ);
        Thread chef = new Chef(sharedQ);
        waiter.start();
        chef.start();
    }
}

class Items{
    String[] items = {" ", "Sandwich",  "Cereal", "Coffee", "Pizza"};
    int[] time = {0,5,3,3,7};

    String getItem(int value){
        return items[value];
    }

    int getTime(int value){
        return time[value];
    }
}

class Waiter extends Thread{
    private final Queue<Integer> sharedQ;
    static int ord = 0;
    Items item = new Items();
    SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss aa");
    public Waiter(Queue<Integer> sharedQ) {
        super("Waiter");
        this.sharedQ = sharedQ;
    }

    @Override
    public void run() {
        int choice = 1;
        Scanner in = new Scanner(System.in);
        while(choice >= 1 && choice <= 4) {
            synchronized (sharedQ) {
                System.out.print("Enter item id :");
                choice = in.nextInt();
                if(choice >= 1 && choice <= 4){
                    ord++;
                    System.out.println("Order Number: ORD"+ord+" for " + item.getItem(choice)+" has been placed at +"+dateFormat.format(new Date()).toString());
                    sharedQ.add(choice);
                    sharedQ.notifyAll();
                }
            }
        }
    }
}

class Chef extends Thread{
    private final Queue<Integer> sharedQ;
    Items item = new Items();
    static int ord = 0;
    SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss aa");
    public Chef(Queue<Integer> sharedQ) {
        super("Chef");
        this.sharedQ = sharedQ;
    }

    @Override
    public void run() {
        int choice;
        while(true) {
            try{
                synchronized (sharedQ) {
                //waiting condition - wait until Queue is not empty
                    while (sharedQ.size() == 0) {
                        sharedQ.wait();
                    }
                    System.out.println(sharedQ.size());
                    choice = sharedQ.poll();
                    System.out.println("abc");
                    ord++;
                    System.out.println("Chef : Picked up ORD"+ord+" at "+ dateFormat.format(new Date()).toString());
                    System.out.println("Chef: Cooking "+item.getItem(choice));
                    Thread.sleep(60*1000*item.getTime(choice));
                    System.out.println("Chef : Finished making "+item.getItem(choice)+" at "+ dateFormat.format(new Date()).toString());
                    sharedQ.notify();
                }
            }
            catch (InterruptedException ex) {
                System.out.println("Exception in chef function");
            }
        }
    }
}

但是,Chef 线程直到 Waiter 线程结束才响应。 有线索吗?

尝试移动

System.out.print("Enter item id :");
choice = in.nextInt();

超出 synchronized 部分。

出现问题是因为 Waiter 线程将大部分时间花在 in.nextInt() 方法中等待用户输入。一直获取锁。当用户输入数字并释放锁时,它几乎会立即返回以进行下一次迭代。如果多个线程尝试获取锁,则决定下一个线程将获得锁的调度程序并不完美,因此它会唤醒 Chef 线程但不会立即获取锁。我们有两个线程都试图获得锁的情况。如果您输入多个数字,您会看到 Chef 有时会被锁定,但并非总是如此。

问题是 Waiter 永远不会释放共享队列上的锁,因此 Chef 永远无法从中读取。

更好的方法是使用 BlockingQueue implementation, like LinkedBlockingQueue, 删除程序中 synchronized 块的使用。

对于新应用程序,应避免使用内部锁(synchronized 块)、Thread 实例和 wait()/notify() 调用,最好使用 ExecutorServicejava.util.concurrent 包中的实用程序。