gpt4 book ai didi

java - 调用 notifyAll() 后线程未唤醒

转载 作者:行者123 更新时间:2023-11-29 07:23:29 25 4
gpt4 key购买 nike

问题是创建 3 个线程,一个每秒打印一个随机数,如果数字是偶数,第二个线程将它平方,如果是奇数,第三个线程将它立方。这应该发生给定的次数(在我的代码中它是无限的,稍后将编辑它)。我的问题是,在第一次迭代之后(即创建一个随机数,正确的线程唤醒并执行其操作),第二个/第三个线程在再次调用 notifyAll() 后不会唤醒。下面显示了我的代码和示例输出。为了调试目的,我添加了一些打印语句:

package com.company;
import java.util.*;


class RandomNumber implements Runnable{

int randomNum = 0;
Random rand = new Random();
boolean flag = false;

public RandomNumber() {
Thread newThread = new Thread(this,"Random Number");
newThread.start();
}

@Override
public synchronized void run()
{

while(flag == false) {
System.out.println("random num thread");
try {
randomNum = rand.nextInt(100) + 1;
System.out.println(randomNum);
flag = true;
notifyAll();
//System.out.println(flag);
Thread.sleep(1000);

} catch (Exception e) {
System.out.println("Exception Caught");
}

}
}

class SquareNumber implements Runnable{

RandomNumber randomNumOb;

public SquareNumber(RandomNumber randNumObject){

this.randomNumOb = randNumObject;
Thread squareThread = new Thread(this, "Square thread");
squareThread.start();

}

@Override
public synchronized void run() {

System.out.println("square thread before while");

while(randomNumOb.flag == true) {
System.out.println("square thread");
if (randomNumOb.randomNum % 2 == 0)
{
System.out.println("Number is even so square of " + randomNumOb.randomNum + " is: " + (randomNumOb.randomNum * randomNumOb.randomNum));

try {
randomNumOb.flag = false;
wait();
}catch(Exception e){
System.out.println("Exception caught");
}
}

else {
try {
System.out.println("inside square else");
wait();
} catch (Exception e) {
System.out.println("Exception Caught");
}

}
}
System.out.println("square thread after while");
}

class CubeNumber implements Runnable{

RandomNumber randomNumOb;

public CubeNumber(RandomNumber randNumObject){

this.randomNumOb = randNumObject;
Thread squareThread = new Thread(this, "Square thread");
squareThread.start();

}

@Override
public synchronized void run() {
System.out.println("cube thread before while");

while(randomNumOb.flag == true) {
System.out.println("cube thread");
if (randomNumOb.randomNum % 2 == 1) {
System.out.println("Number is odd so cube of " + randomNumOb.randomNum + " is: " + (randomNumOb.randomNum * randomNumOb.randomNum * randomNumOb.randomNum));
try {
randomNumOb.flag = false;
wait();
}catch (Exception e){

}
}

else {
try {
System.out.println("inside cube else");
//randomNumOb.flag = false;
wait();
} catch (Exception e) {
System.out.println("Exception Caught");
}

}
}
System.out.println("cube thread after while");

}

public class Main {

public static void main(String[] args) {

RandomNumber random = new RandomNumber();
SquareNumber square = new SquareNumber(random);
CubeNumber cube = new CubeNumber(random);
}

示例输出:

random num thread
81
square thread before while
square thread
inside square else
cube thread before while
cube thread
Number is odd so cube of 81 is: 531441
random num thread
68

似乎方形或立方体线程在此之后都没有醒来并且无法弄清楚为什么。任何帮助,将不胜感激。

最佳答案

为了锁定和等待/通知工作,需要一个共享锁。

每个对象都有一个“内在锁”。锁作为等待和通知的通信枢纽。将 synchronized 放在实例方法上意味着调用该方法的线程在进入方法时获取实例的内部锁,并在离开时释放内部锁。 wait/notify/notifyAll 方法只能由持有内部锁的线程调用。

当线程调用 wait 时,它会释放锁并且线程会进入 hibernate 状态,直到它收到通知(或被中断)。锁跟踪当前哪些线程正在等待它,这称为等待集。

当线程调用 notify 时,它告诉调度程序从锁的等待集中选择一个线程并向其发送通知。 notifyAll 方法是相同的,只是它唤醒了等待集中的所有其他线程。

这就是锁定决定通知哪个等待线程的方式。

因此在发布的代码中,这些 Runnable 中的每一个都获得了自己的内在锁并且没有共享。唤醒通知必须由另一个线程引起,该线程已获取等待线程调用 wait on 的锁。

在这里你可以在入口点类中创建一个公共(public)锁

final Object lock = new Object();  // value referenced by lock must not change

并将其传递到构造函数中的不同 Runnables,例如:

public SquareNumber(RandomNumber randNumObject, Object lock){ 
this.lock = lock;
...

所以他们使用相同的锁。然后将 wait 和 notify 方法调用更改为使用该共享锁对象,并将同步方法更改为传入锁的同步块(synchronized block)。

关于添加到 RandomNumber runnable 的 sleep :notifyAll 在当前线程释放锁之前不会生效(因为每个等待线程都必须获取锁才能离开 wait 方法)。睡在这里不会给通知时间做任何事情,它只是防止任何事情发生。

关于java - 调用 notifyAll() 后线程未唤醒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59288934/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com