【发布时间】:2018-02-13 12:37:50
【问题描述】:
我正在尝试理解 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) 当这些线程中的任何一个通过在对象objectToWaitOn(这些线程之间共享)上调用notifyAll() 来释放锁时,它会立即释放锁吗?我有这个疑问是因为这些线程位于基于objectToWaitOn 对象的synchronized 块中;所以即使一个线程调用了 notifyAll(),它不应该因为它在同步块中而仍然持有锁?
2) 当一个线程通过在objectToWaitOn 上调用wait() 处于等待状态,并且如果其他线程通过调用notifyAll() 释放了锁,等待线程等待释放还是别的什么?无论如何,从synchronized 块中出来的线程不会释放它所持有的对象上的锁吗?所以在上面的例子中,如果一个线程在objectToWaitOn 上持有锁并且从synchronized 块中出来,它是否无论如何都不会释放objectToWaitOn 的锁,并且不应该基于此唤醒另一个线程?
谁能帮我澄清这些疑惑?
【问题讨论】:
标签: java multithreading synchronization