为了测试我的理解等等通知我写了一个小程序,按特定顺序写left
right
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) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
int i=0;
while (i++ < 10) {
System.out.println("Left ");
monitor.notify();
monitor.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 ");
monitor.notify();
monitor.wait();
}
}
}
}
但我知道写下面的代码很糟糕:
monitor.wait();
我应该循环包装。
但我无法想象循环条件,因为状态不会改变。
请建议如何解决这个问题。
答案 0 :(得分:0)
你的程序 有共享状态,你还没有编写它。你的程序在当前的实现中不会“工作”,因为通知可以由任何一条腿接收,所以你的腿可以按任何顺序进行(即可以重复进行)。缺少的“共享状态”是“轮到它”。每条腿只应在转弯时进行,然后应该转弯到另一条腿并通知。你的while循环应该基于当前的转弯值。
答案 1 :(得分:0)
这是一段代码,其中包含一些更改,说明如何在循环中使用notify和wait
public class SomeTest {
public enum Step {
Left,
Right
}
public static void main(String[] args) throws InterruptedException {
final AtomicReference<Step> currentStep = new AtomicReference<Step>(Step.Left);
new LeftLegThread(currentStep).start();
new RightLegThread(currentStep).start();
Thread.sleep(10*1000);
System.exit(0);
}
}
class LeftLegThread extends Thread {
private final AtomicReference<SomeTest.Step> currentStep;
public LeftLegThread(AtomicReference<SomeTest.Step> str) {
currentStep = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (currentStep) {
while(currentStep.get().equals(SomeTest.Step.Left))
currentStep.wait();
currentStep.set(SomeTest.Step.Left);
currentStep.notify();
}
}
}
class RightLegThread extends Thread {
private final AtomicReference<SomeTest.Step> currentStep;
public RightLegThread(AtomicReference<SomeTest.Step> str) {
currentStep = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (currentStep) {
while(currentStep.get().equals(SomeTest.Step.Right))
currentStep.wait();
currentStep.set(SomeTest.Step.Right);
currentStep.notify();
}
}
}
答案 2 :(得分:0)
我认为正确的方法是使用两个锁。例如,一个用于右腿和左腿。左侧线程通知右侧,右侧线程通知左侧。 (经过10次循环迭代后,代码会永远等待。您可能希望自己解决这个问题。)
你的循环条件可以简单地用枚举来切换腿。
public class Example {
public static void main(String[] args) throws Exception {
Object left = new Object();
Object right = new Object();
LegHolder legHolder = new LegHolder();
legHolder.leg = Leg.LEFT;
new LeftLegThread(left, right, legHolder).start();
new RightLegThread(left, right, legHolder).start();
}
}
enum Leg {
LEFT, RIGHT
}
class LegHolder {
protected volatile Leg leg;
}
class LeftLegThread extends Thread {
private final Object left;
private final Object right;
private final LegHolder holder;
public LeftLegThread(Object left, Object right, LegHolder holder) {
this.left = left;
this.right = right;
this.holder = holder;
}
@Override
public void run() {
try {
int i = 0;
while (i++ < 10) {
synchronized (left) {
System.out.println("Left ");
synchronized (right) {
holder.leg = Leg.RIGHT;
right.notify();
}
while (holder.leg != Leg.LEFT)
left.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class RightLegThread extends Thread {
final Object left;
final Object right;
private final LegHolder holder;
public RightLegThread(Object left, Object right, LegHolder holder) {
this.left = left;
this.right = right;
this.holder = holder;
}
@Override
public void run() {
try {
synchronized (right) {
while (true) {
System.out.println("Right ");
synchronized (left) {
holder.leg = Leg.LEFT;
left.notify();
}
while (holder.leg != Leg.RIGHT)
right.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}