此代码从两个不同的线程打印偶数/奇数。在这里,我的程序卡在wait()中,无法使用notifyAll()唤醒睡眠线程。
想知道,为什么notifyAll无法唤醒所有睡眠的线程? 需要知道我在这里做错了。
class EvenOddThread {
public static void main (String [] args) {
Runnable runnEven = new ThreadPrint (true, 10);
Runnable runnOdd = new ThreadPrint (false, 10);
Thread t1 = new Thread (runnEven);
Thread t2 = new Thread (runnOdd);
t1.start ();
t2.start ();
}
}
class ThreadPrint implements Runnable {
private boolean isEvenPrint = false;
private int maxPoint = 0;
ThreadPrint (boolean isEven, int max) {
isEvenPrint = isEven;
maxPoint = max;
}
@Override
public void run () {
Print p = new Print();
if (isEvenPrint)
p.printEven(maxPoint);
else
p.printOdd(maxPoint);
}
}
class Print {
public synchronized void printEven (int maxPoint) {
int even = 0;
while (even <= maxPoint) {
System.out.println(even);
even = even + 2;
try {
wait();
}
catch (Exception e) {
System.out.println(e);
}
notifyAll();
}
}
public synchronized void printOdd (int maxPoint) {
int odd = 1;
while (odd <= maxPoint) {
System.out.println(odd);
odd = odd + 2;
try {
wait();
}
catch (Exception e) {
System.out.println(e);
}
notifyAll();
}
}
}
谢谢, 湿婆
答案 0 :(得分:3)
两个线程在打印第一个数字后都输入wait
。由于两个线程都已暂停,因此任何一个线程都无法唤醒另一个线程。
为了使一对线程以这种方式交替,您可以具有控制每个线程进度的单独条件。每个线程在完成自己的工作单元后将取消阻塞另一个线程。可以使用Semaphore,CyclicBarrier或Phaser来完成。
答案 1 :(得分:1)
notifyAll()应该通知所有在特定对象上等待的线程,而不是所有在任何地方等待的线程。您要做的是,为每个线程创建一个Print实例-然后使用非限定的wait()和notifyAll()-这意味着您的线程使用每个线程本地的变量进行通信。
因此,首先您必须使它们使用相同的同步/信号对象。
第二,至少需要提供一些初始踢。请务必小心,因为当您确定其中至少有一个已经在收听时,您需要发出此信号。最好的情况是确保他们俩都在听,这样您就可以避免无数种可能的种族状况。
= rant = Sun在这里通过隐藏程序员的(互斥量,条件,信号)三合会而使IMO陷入困境,这很可能是为了简化多线程。他们失败了。 = / rant =
答案 2 :(得分:1)
似乎您只希望两个线程以乒乓方式打印奇/偶数。然后,您可以使用ReentrantLock
。有几种方法可以做到这一点。
I。锁
public static final ReentrantLock lock = new ReentrantLock();
public static final int LIMIT = 50;
public static int toPrint = 0;
public static void main(String[] args){
Thread t1 = new Thread(() -> {
while (true){
try {
lock.lock();
if(toPrint > LIMIT) break;
else if(toPrint % 2 == 0) {
System.out.println(toPrint++);
}
} finally {
lock.unlock();
}
}
});
Thread t2 = new Thread(() -> {
while (true) {
try {
lock.lock();
if (toPrint > LIMIT) break;
else if (toPrint % 2 == 1) {
System.out.println(toPrint++);
}
} finally {
lock.unlock();
}
}
});
t1.start();
t2.start();
}
II。易挥发 (易碎,但有效)
public static final int LIMIT = 50;
public static volatile int toPrint = 0;
public static void main(String[] args){
Thread t1 = new Thread(() -> {
while (true){
int cur = toPrint;
if(cur > LIMIT) break;
else if(cur % 2 == 0){
System.out.println(cur);
toPrint = cur + 1;
}
}
});
Thread t2 = new Thread(() -> {
while (true) {
int cur = toPrint;
if(cur > LIMIT) break;
else if(cur % 2 == 1){
System.out.println(cur);
toPrint = cur + 1;
}
}
});
t1.start();
t2.start();
}
答案 3 :(得分:0)
class EvenOddThread {
public static void main (String [] args) {
Runnable runnEven = new ThreadPrint (10);
Thread t1 = new Thread (runnEven);
Thread t2 = new Thread (runnEven);
t1.start ();
t2.start ();
}
}
class ThreadPrint implements Runnable {
private int maxPoint = 0;
private int counter = 0;
ThreadPrint (int max) {
maxPoint = max;
}
@Override
public void run () {
while (counter <= maxPoint) {
synchronized(this) {
if (counter % 2 == 0) {
System.out.println("By Thread" + Thread.currentThread().getName() +" :: "+ counter);
counter ++;
notify();
try {
wait();
}
catch (Exception e) {
System.out.println(e);
}
}
else if (counter % 2 != 0){
System.out.println("By Thread" + Thread.currentThread().getName() +" :: "+ counter);
counter ++;
notify();
try {
wait();
}
catch (Exception e) {
System.out.println(e);
}
}
}
}
}
}
谢谢大家的回答,但我得到了 here找出我该怎么做才能更正我的代码。
现在,它以我想要的方式工作。 :)