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