如果线程没有改变状态,如何使用内部标志进行等待循环?

时间:2014-04-22 13:47:48

标签: java multithreading concurrency synchronization

为了测试我的理解等等通知我写了一个小程序,按特定顺序写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();

我应该循环包装。

但我无法想象循环条件,因为状态不会改变。

请建议如何解决这个问题。

3 个答案:

答案 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();
        }
    }
}