java - notifyAll() 的多线程问题

标签 java multithreading

我正在做一个练习,模拟商店中具有多个线程的等待队列。

我有一个等候名单和 2 个柜台 当某个客户端排在等待列表的第一位并且柜台有空闲时,该客户端进入柜台等待2秒,通知其他客户端然后离开。

我不明白为什么等待的客户永远不会收到通知。 (我阅读了许多其他主题,但找不到答案)。

package tp;
import java.util.Random;
public class Client extends Thread{

    private static Counters counters = new Counters(2);
    private static WaitingQueue queue = new WaitingQueue(3);
    private static Random random = new Random();
    private static Integer client_counter = 1;
    private Integer id;

    public Client(){
        this.id = client_counter++;
    }

    public static void main(String[] args) {
        while (true) {
            try {
                Thread.sleep(500);
                Client client = new Client();
                client.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

   public void run() {   
       boolean end = false;
       System.out.printf("Client %d come in the shop\n", this.id);
       if (queue.enter(this)) { // false if queue is full
           System.out.printf("Client %d go in the waiting queue\n", this.id);
           while (!end) {
               try {
                   end = this.waitToEnter();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       }
   }

    private synchronized boolean waitToEnter() throws InterruptedException{
        while ( (!queue.isFirst(this))) { 
// return true if client is first in the queue
            System.out.printf("Client %d wait to be first\n", this.id);
            wait();

        }
        int nb = counters.entrer(this); 
// return -1 if no free counter else index of the counter
        while (nb == -1) {
            System.out.printf("Client %d for a free counter\n", this.id);
            wait();
            nb = counters.entrer(this);
        }
        this.enterCounter(nb);
        notifyAll();
        return true;
    }

    private void enterCounter(int nb) throws InterruptedException {
        queue.leave(this);
        System.out.printf("Client %d in counter %d\n", this.id, nb);
        this.sleep((long) 2000 + random.nextInt(1000));
        System.out.printf("Client %d out of counter %d\n", this.id, nb);
        counters.leave(this, nb);
    }
}



package tp;

import java.util.ArrayList;

public class Counters {

    private ArrayList<Boolean> counters = new ArrayList<Boolean>();

   public Counters(int nb_guichets) {
       /* Set all counter to free*/
       for (int i = 0; i < nb_guichets; i++) {
            counters.add(i, true);
       }
   }

   public synchronized int entrer(Client client) {
       /* if a counter is free return its index else -1 */
       for (int i = 0; i < counters.size(); i++) {
           if (counters.get(i)) {
               counters.set(i,false);
               return i;
           }
       }
       return -1;
   }

   public void leave(Client client, int nb) {
       counters.set(nb, true);
   }
}




package tp;
import java.util.ArrayList;

public class WaitingQueue {

    public ArrayList<Client> waiting_list = new ArrayList();
    private int waiting_list_size;

   public WaitingQueue(int size) {
      this.waiting_list_size = size;
   }

   public boolean isEmpty() {

       return waiting_list.size() == 0;
   }

   public boolean isFirst(Client client) {
      return waiting_list.get(0).equals(client);
   }

   public synchronized boolean enter(Client client) {
      boolean res = false;
      if(waiting_list.size() < waiting_list_size) {
          res = waiting_list.add(client);
      }
      return res;
   }

   public synchronized void leave(Client client) {
      waiting_list.remove(client);
   }
}

日志:

Client 1 come in the shop
Client 1 go in the waiting queue
Client 1 in counter 0
Client 2 come in the shop
Client 2 go in the waiting queue
Client 2 in counter 1
Client 3 come in the shop
Client 3 go in the waiting queue
Client 3 for a free counter
Client 4 come in the shop
Client 4 go in the waiting queue
Client 4 wait to be first
Client 5 come in the shop
Client 5 go in the waiting queue
Client 5 wait to be first
Client 1 out of counter 0
Client 6 come in the shop
Client 2 out of counter 1
Client 7 come in the shop
Client 8 come in the shop

最佳答案

waitnotify/notifyall 对它们被调用的对象起作用。您正在创建许多不同的客户端对象,因此每个对象都有自己的监视器。

您可能应该坚持使用 java.util.concurrent 包中的类来进行同步(例如,Semaphore)。

如果您想坚持使用对象同步方法(作为练习),您需要修改代码以拥有一个可供等待和通知的对象。

关于java - notifyAll() 的多线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30104631/

相关文章:

java - 确定音频处理中的延迟

c# - 如何强制 FileSystemWatcher 等待文件下载?

java - 一个 Java 线程如何检查另一个线程的状态,例如另一个是否被阻止?

java - Quartz 调度程序和 NextFireTime

java - 如何在使用 Collat​​or 排序时避免忽略连字符

java - Swing JPanel - 绘制的图形复制而不是移动

iphone - UISearchDisplayController 和大量数据的搜索性能

java - 接受父类(super class)作为参数,但在方法中使用子类

java - 如何保留 lambda 的参数类型?

java - 总行数结果集 getRow 方法