我试图理解java核心同步。
我写了代码示例:
程序应写入
left右侧
10倍
package concurrency;
public class LeftRightWaitNotifyExample {
final static String str = "1";
public static void main(String[] args) {
new LeftLegThread(str).start();
new RightLegThread(str).start();
}
}
class LeftLegThread extends Thread {
String monitor;
public LeftLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
for (int i = 0; i < 10; i++) {
System.out.println("Left ");
wait();
}
}
}
}
class RightLegThread extends Thread {
String monitor;
public RightLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
while (true) {
System.out.println("Right ");
notify();
wait();
}
}
}
}
我得到这个输出:
Left
Right
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at concurrency.LeftLegThread.makeStep(LeftRightWaitNotifyExample.java:35)
at concurrency.LeftLegThread.run(LeftRightWaitNotifyExample.java:23)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at concurrency.RightLegThread.makeStep(LeftRightWaitNotifyExample.java:61)
at concurrency.RightLegThread.run(LeftRightWaitNotifyExample.java:51)
在此之前,当我在synchronized
块内使用wait
方法时出现此错误。但在这里,我使用synchronized
块内的等待
问题的原因是什么?如何解决?
更新
我根据建议重写代码:
public class LeftRightWaitNotifyExample {
final static String str = "1";
public static void main(String[] args) throws InterruptedException {
new LeftLegThread(str).start();
Thread.sleep(100);
new RightLegThread(str).start();
}
}
class LeftLegThread extends Thread {
String monitor;
public LeftLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
for (int i = 0; i < 2; i++) {
System.out.println("Left ");
monitor.wait();
monitor.notify();
}
}
}
}
class RightLegThread extends Thread {
String monitor;
public RightLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
while (true) {
System.out.println("Right ");
monitor.notify();
monitor.wait();
}
}
}
}
电流输出:
Left
Right
Left
Right
Right
为什么Right
只出3而Left
只出两次。为什么?
您在monitor
上进行同步,因此也应该在监视器上进行wait()
:
monitor.wait();
现在您正在等待this
,它不是监视器的所有者,因为同步在monitor
上。
请注意,notify
当然也应该在monitor
对象上完成,并且您可能需要考虑在两个线程中使用notify
/notifyAll
。否则,可能会发生一个线程在等待丢失的通知。使用超时(wait
的重载版本)也可能是捕捉角落案例的好主意。
原因-The current thread is not the owner of the object's monitor
.若要调用wait()
方法,当前线程必须拥有此对象的监视器
在您的情况下,您获得的是monitor
对象上的监视器,而不是当前对象(此对象)。
您正试图锁定监视器对象。但它是锁定线程对象(LeftLegThread,RightLegThread)。实际上它并没有被同步锁定。
monitor.wait();将修复。
public class LeftRightWaitNotifyExample {
final static String str = "1";
public static void main(String[] args) throws InterruptedException {
new LeftLegThread(str).start();
Thread.sleep(1000);
new RightLegThread(str).start();
}
}
class LeftLegThread extends Thread {
String monitor;
public LeftLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
while (true) {
System.out.println("Left ");
monitor.wait();
monitor.notify();
Thread.sleep(1000);
}
}
}
}
class RightLegThread extends Thread {
String monitor;
public RightLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
while (true) {
System.out.println("Right ");
monitor.notify();
monitor.wait();
Thread.sleep(1000);
}
}
}
}