我正在做一个练习,模拟商店中具有多个线程的等待队列。
我有一个等候名单和 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
最佳答案
wait
和 notify
/notifyall
对它们被调用的对象起作用。您正在创建许多不同的客户端对象,因此每个对象都有自己的监视器。
您可能应该坚持使用 java.util.concurrent
包中的类来进行同步(例如,Semaphore
)。
如果您想坚持使用对象同步方法(作为练习),您需要修改代码以拥有一个可供等待和通知的对象。
关于java - notifyAll() 的多线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30104631/