Java notifyAll()的多线程问题

Java notifyAll()的多线程问题,java,multithreading,Java,Multithreading,我正在做一个练习,用多个线程模拟商店中的等待队列 我有一张等候名单和两个柜台 当一个客户是等待名单中的第一个,并且一个柜台空闲时,客户进入柜台等待2秒,通知其他客户然后离开 我不明白为什么等待的客户从未得到通知。 (我读了很多其他的话题,但找不到答案) wait和notify/notifyall处理调用它们的对象。您正在创建许多不同的客户端对象,因此每个对象都有自己的监视器 您可能应该坚持使用java.util.concurrent包中的类来进行同步(例如,Semaphore) 如果您想坚持使用

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

我有一张等候名单和两个柜台 当一个客户是等待名单中的第一个,并且一个柜台空闲时,客户进入柜台等待2秒,通知其他客户然后离开

我不明白为什么等待的客户从未得到通知。 (我读了很多其他的话题,但找不到答案)


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

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


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

此代码需要执行以下操作:

使用线程实例作为监视对象 因此,每个线程都只对自己进行“notifyall”。也就是说,当“客户端1”离开计数器并执行notifyAll()时,它正在执行client1.notifyAll()。客户端3已完成client3.wait()。因此,您正在通知不正确的监视器对象

我建议您在wait()或notify()之前使用始终显式对象。在本例中是this.wait(),不正确

我还没有这样做,但很容易看出这一点,如果使用jconsole,则必须有三个线程处于“等待状态”,其中两个线程处于第一个等待()状态,另一个线程处于第二个等待()

这里有两个不同的条件 您正在使用一个notify for来处理不同的事情:通知您正在离开队列,而您正在离开柜台。。。这是更好的使用条件

您正在使用线程主体上的监视器,而不是资源主体上的监视器 它位于队列方法和计数器方法上,我将在其中放置此监视器

试试这个(或者最好不要,最好自己动手) 如果您想使用wait/notify作为练习,请尝试这种方式(我尝试尽可能少地修改您的代码,但我没有尝试过,这不是一种好方法,有条件的话会更好)

tp包;
导入java.util.Random;
公共类客户端扩展线程{
专用静态计数器=新计数器(2);
私有静态等待队列=新的等待队列(3);
私有静态随机=新随机();
专用静态整数客户端\ u计数器=1;
私有整数标识;
公共整数getIdentity(){
返回身份;
}
公共void setIdentity(整数标识){
这个。身份=身份;
}
私有静态对象监视器=新对象();
公共客户机(){
this.identity=client_counter++;
}
公共静态void main(字符串[]args){
while(true){
试一试{
睡眠(500);
客户端=新客户端();
client.start();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公开募捐{
布尔结束=假;
System.out.printf(“客户端%d进入商店\n”,此.identity);
如果(queue.enter(this)){//false,如果队列已满
System.out.printf(“客户端%d进入等待队列\n”,此.identity);
当(!结束){
试一试{
end=this.waitToEnter();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
System.out.printf(“客户%d离开商店,\n”,此.identity);
}
私有布尔waitToEnter()抛出InterruptedException{
队列。waitTillFirst(此);
System.out.printf(“客户端%d是队列中的第一个,\n”,此.identity);
int nb=counters.waitTillEnter(此);
排队。离开(这个);
这是一个计数器(nb);
返回true;
}
私有void enterCounter(int nb)抛出InterruptedException{
System.out.printf(“计数器%d中的客户端%d\n”,this.identity,nb);
这个.sleep((long)2000+random.nextInt(1000));
System.out.printf(“客户端%d离开计数器%d\n”,this.identity,nb);
离开(本,nb);
}
}
包装tp;
导入java.util.ArrayList;
公共类柜台{
私有ArrayList计数器=新ArrayList();
公共柜台(国际柜台){
/*将所有计数器设置为自由*/
对于(int i=0;ipackage 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
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 identity;
    public Integer getIdentity() {
        return identity;
    }

    public void setIdentity(Integer identity) {
        this.identity = identity;
    }

    private static Object monitor = new Object();

    public Client() {
        this.identity = 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.identity);
        if (queue.enter(this)) { // false if queue is full
            System.out.printf("Client %d go in the waiting queue\n", this.identity);
            while (!end) {
                try {
                    end = this.waitToEnter();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.printf("Client %d leave the shop\n", this.identity);
    }

    private  boolean waitToEnter() throws InterruptedException {
        queue.waitTillFirst(this);
        System.out.printf("Client %d is the first in queue\n", this.identity);
        int nb = counters.waitTillEnter(this);
        queue.leave(this);
        this.enterCounter(nb);
        return true;

    }

    private void enterCounter(int nb) throws InterruptedException {
        System.out.printf("Client %d in counter %d\n", this.identity, nb);
        this.sleep((long) 2000 + random.nextInt(1000));
        System.out.printf("Client %d out of counter %d\n", this.identity, 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 synchronized void  leave(Client client, int nb) {
        counters.set(nb, true);
        notifyAll();
    }

    public synchronized int waitTillEnter(Client client) throws InterruptedException {
        int nb = entrer(client);
        // return -1 if no free counter else index of the counter
        while (nb == -1) {
            System.out.printf("Client %d waiting for a free counter\n", client.getIdentity());
            wait();
            nb = entrer(client);
        }
        return nb;
    }
}
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);
      notifyAll();
   }

    public synchronized void waitTillFirst(Client client) throws InterruptedException {
        while ((!isFirst(client))) {
            // return true if client is first in the queue
            System.out.printf("Client %d wait to be first\n", client.getIdentity());
            wait();
        }

    }
}
// Put the current thread in Waiting State
Synchronized(sharedInstance) {
   sharedInstance.Wait()
}

// Wakes up all the thread sharing sharedInstance
Synchronized(sharedInstance) {
   sharedInstance.NotifyAll()
}