问题是创建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
在此之后,似乎平方线程或立方线程都没有唤醒,并且无法弄清原因。任何帮助,将不胜感激。
答案 0 :(得分:5)
要进行锁定并等待/进行通知,必须有一个共享锁。
有一个“内在锁”,被烘烤到每个物体中。该锁用作等待和通知的通信中心。将同步放在实例方法上意味着,调用该方法的线程在进入该方法时会获取该实例的固有锁定,并在离开该实例时释放该固有锁定。 wait / notify / notifyAll方法只能由持有内部锁的线程调用。
当线程调用等待时,它将释放锁定,并且线程将进入休眠状态,直到收到通知(或被中断)。该锁跟踪当前正在等待哪些线程,这就是等待集。
当线程调用notify时,它告诉调度程序从锁的等待集中选择一个线程并向其发送通知。 notifyAll方法是相同的,除了它唤醒等待集中的所有其他线程。
这就是锁定确定通知哪个等待线程的方式。
因此,在已发布的代码中,每个Runnable都获取自己的固有锁,并且没有共享。唤醒通知必须由另一个线程获得,该线程已获得等待线程调用wait的锁。
在这里您可以在入口点类中创建通用锁
final Object lock = new Object(); // value referenced by lock must not change
并将其传递到构造函数中的不同Runnable中,例如:
public SquareNumber(RandomNumber randNumObject, Object lock){
this.lock = lock;
...
,所以他们使用相同的锁。然后,更改等待和通知方法调用以使用该共享锁对象,并将同步方法更改为传递了锁的同步块。
关于添加到RandomNumber可运行状态的睡眠的详细信息:notifyAll直到当前线程释放锁后才生效(因为每个等待线程都必须获取锁才能离开wait方法)。在这里睡觉并没有做任何事情来给通知时间上班,只是阻止了任何事情的发生。
答案 1 :(得分:0)
CubeNumber
和SquareNumber
都都等待它们自己的对象上的通知,而不是等待随机对象上的通知。因此他们永远不会收到通知。
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 void run()
{
while(flag == false) {
System.out.println("random num thread");
try {
randomNum = rand.nextInt(100) + 1;
System.out.println(randomNum);
flag = true;
synchronized(this) {
notifyAll();
}
//System.out.println(flag);
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("Exception Caught");
}
}
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;
synchronised(randomNumOb) {
randomNumOb.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");
}
与方形版本相同。
但是,另一个问题是,您无法保证多维数据集和平方方法都将在randomnumber的睡眠秒内运行。 可能在这里使用后代。