我正在阅读Herbert Schildt的《Java完整参考》一书中Java
中的multi threading
。我遇到了以下代码[Pg.252,7th ed.],它解释了wait()
和notify()
在现代Java
中对suspend
和resume
线程的使用。我的问题是关于关键字synchronization
在以下代码中的两个位置的重要性(在类NewThread
的run()
方法中(:
// Suspending and resuming a thread the modern way.
class NewThread implements Runnable {
String name;
Thread t;
boolean suspendFlag;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
suspendFlag = false;
t.start();
}
// This is the entry point for thread.
public void run() {
try {
for (int i = 15; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
synchronized (this) { //First doubt here
while (suspendFlag) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
void mysuspend() {
suspendFlag = true;
}
synchronized void myresume() { //Second doubt here
suspendFlag = false;
notify();
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
try {
Thread.sleep(1000);
ob1.mysuspend();
Thread.sleep(1000);
ob1.myresume();
ob2.mysuspend();
Thread.sleep(1000);
ob2.myresume();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
//some code
}
我的疑问:我知道关键字synchronization
的使用,即只允许一个线程在同一对象上输入同步方法,但这里我们有两个线程在两个不同的对象上运行。那么,以上代码中使用的两个synchronization
关键字有什么意义呢。
我尝试运行上面的代码,在每个地方同时删除不同的synchronized
关键字。我得到了同样的错误:java.lang.IllegalMonitorStateException: current thread is not owner
不同的次数和不同的行号,这取决于我是同时删除还是只删除一个(以及哪一个(synchronization
关键字。我查找了上面的错误,并在这里找到了解释,但仍然无法将答案与我的怀疑联系起来。
synchronized
解决的问题是,它允许两个线程对共享的suspendFlag
变量有一个一致的视图。
在一些实际程序中,线程可能会在设置susependFlag=false
之前设置其他共享变量。如果未使用synchronized
,则等待线程可以唤醒,并查看suspendFlag==false
,但不请查看其他变量集。或者更糟的是,它可能会看到其中一些场景,但不会看到其他场景。
如果没有同步,Java不能保证不同的线程将看到以相同顺序更新的变量。
我得到了同样的错误:java.lang.IollegalMonitorStateException:当前线程不是所有者。
Java库试图通过强制在允许您使用wait()
和notify()
之前使用synchronized
来帮助您。规则很简单:只能从synchronized(o)
块内的代码中调用o.wait()
、o.notify()
或o.notifyAll()
。如果您违反了该规则,那么库将抛出异常。
当您的代码调用o.wait()
时,wait((调用会暂时解锁监视器锁,以便其他线程能够在o
上同步并调用o.notify()
。o.wait()
调用保证在返回之前重新锁定o
。