我正在尝试理解Java中的线程间通信,并了解到可以使用wait()
、notify()
和notifyAll()
方法来实现。
为了让线程执行这些方法之一,线程需要成为调用(任何一个)方法的对象的lock
的所有者。此外,所有这些方法都需要在一个synchronized
块/方法中。到目前为止,一切正常。
我尝试编写了一个程序,在其中一个线程打印奇数,另一个线程打印偶数。程序可以正确运行,但同时也引发了一些疑问。
下面是我实现的程序的完整源代码。
PrintEvenNumThread.java // 打印偶数
package com.example.multithr.implrun;
import com.example.common.ObjectToWaitOn;
public class PrintEvenNumThread implements Runnable {
private ObjectToWaitOn objectToWaitOn;
public PrintEvenNumThread(ObjectToWaitOn objectToWaitOn) {
this.objectToWaitOn = objectToWaitOn;
}
@Override
public void run() {
int numToPrint = 2;
for (;;) {
synchronized (objectToWaitOn) {
while(objectToWaitOn.getPrintEvenOrOdd() != 2) {
try {
objectToWaitOn.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
objectToWaitOn.print("EvenThread",numToPrint);
numToPrint += 2; // Generate next even number
objectToWaitOn.setPrintEvenOrOdd(1);
objectToWaitOn.notifyAll();
}
}
}
}
PrintOddNumsThread.java // 打印奇数
package com.example.multithr.implrun;
import com.example.common.ObjectToWaitOn;
public class PrintOddNumsThread implements Runnable {
private ObjectToWaitOn objectToWaitOn;
public PrintOddNumsThread(ObjectToWaitOn objectToWaitOn) {
this.objectToWaitOn = objectToWaitOn;
}
@Override
public void run() {
int numToPrint = 1;
for(;;) {
synchronized(objectToWaitOn) {
while(objectToWaitOn.getPrintEvenOrOdd() != 1) {
try {
objectToWaitOn.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
objectToWaitOn.print("OddThread", numToPrint);
numToPrint += 2; // Generate next odd number
objectToWaitOn.setPrintEvenOrOdd(2);
objectToWaitOn.notifyAll();
}
}
}
}
ObjectToWaitOn.java // 用于线程间通信的“共享”对象
package com.vipin.common;
public class ObjectToWaitOn {
private int printEvenOrOdd;
public ObjectToWaitOn(int printEvenOrOdd) {
this.printEvenOrOdd = printEvenOrOdd;
}
public int getPrintEvenOrOdd() {
return printEvenOrOdd;
}
public void setPrintEvenOrOdd(int printEvenOrOdd) {
this.printEvenOrOdd = printEvenOrOdd;
}
public void print(String byThread, int numToPrint) {
System.out.println(byThread + ": " +numToPrint);
}
}
PrintEvenOddNumsMainApp.java
package com.example.multithr.main.app1;
import com.example.common.ObjectToWaitOn;
import com.example.multithr.implrun.PrintEvenNumThread;
import com.example.multithr.implrun.PrintOddNumsThread;
public class PrintEvenOddNumsMainApp {
public static void main(String[] args) {
ObjectToWaitOn obj = new ObjectToWaitOn(1); // 1 == odd; 2 == even
PrintEvenNumThread printEvenNumThread = new PrintEvenNumThread(obj);
PrintOddNumsThread printOddNumsThread = new PrintOddNumsThread(obj);
Thread evenNum = new Thread(printEvenNumThread);
Thread oddNum = new Thread(printOddNumsThread);
evenNum.start();
oddNum.start();
}
}
我的疑问是:
1)当这些线程中的任何一个通过调用notifyAll()
在共享的objectToWaitOn
对象上释放锁定时,它是否立即释放锁定?我有这个疑问,因为这些线程基于objectToWaitOn
对象的synchronized
块;因此,即使线程调用了notifyAll(),它是否仍然保持锁定,因为它处于同步块中?
2) 当线程通过在objectToWaitOn
上调用wait()
处于等待状态时,如果其他线程通过调用notifyAll()
释放了锁定,则等待线程会等待锁定释放还是其他事情?不管怎样,一个线程离开同步块时总会释放它所持有的对象上的锁定;因此,在上面的示例中,如果一个线程持有objectToWaitOn
的锁定并离开同步块,它是否会为objectToWaitOn
释放锁定,并且根据这个,其他线程会醒来吗?
谁能帮我澄清这些疑虑?