Java 如果线程不';不改变状态?

Java 如果线程不';不改变状态?,java,multithreading,concurrency,synchronization,Java,Multithreading,Concurrency,Synchronization,为了测试我的理解能力,我编写了一个小程序,它以特定的顺序写左右 public class LeftRightWaitNotifyExample { final static String str = "1"; public static void main(String[] args) throws InterruptedException { new LeftLegThread(str).start(); Thread.sleep(100);

为了测试我的理解能力,我编写了一个小程序,它以特定的顺序写

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();
            }
        }
    }
}
我应该把它绕成圈

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


请给出解决此问题的建议。

您的程序确实具有共享状态,但您还没有编写它。您的程序在其当前实现中不会“工作”,因为通知可以由任何一个分支接收,因此您的分支可以按任何顺序运行(即,一个分支可以重复运行)。缺少的“共享状态”是“轮到谁了”。每一条腿只应在轮到它们时继续前进,然后它应将转弯传递给另一条腿并通知。您的while循环应基于当前的回合值。

下面是一段代码,其中包含一些更改,说明了如何使用notify和wait in循环

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();

        }
    }
}
公共类测试{
公共枚举步骤{
左边
赖特
}
公共静态void main(字符串[]args)引发InterruptedException{
最终原子参考currentStep=新原子参考(步骤左);
新的LeftLegThread(currentStep).start();
新的RightLegThread(currentStep).start();
线程。睡眠(10*1000);
系统出口(0);
}
}
类LeftLegThread扩展线程{
私有最终原子参考步骤;
公共LeftLegThread(原子引用str){
currentStep=str;
}
@凌驾
公开募捐{
试一试{
makeStep();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
私有void makeStep()引发InterruptedException{
已同步(currentStep){
while(currentStep.get().equals(SomeTest.Step.Left))
currentStep.wait();
currentStep.set(SomeTest.Step.Left);
currentStep.notify();
}
}
}
类RightLegThread扩展线程{
私有最终原子参考步骤;
公共RightLegThread(原子引用str){
currentStep=str;
}
@凌驾
公开募捐{
试一试{
makeStep();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
私有void makeStep()引发InterruptedException{
已同步(currentStep){
while(currentStep.get().equals(SomeTest.Step.Right))
currentStep.wait();
currentStep.set(SomeTest.Step.Right);
currentStep.notify();
}
}
}

我认为正确的方法是使用两个锁。例如,右腿和左腿各有一个。左线程通知右线程,右线程通知左线程。(经过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();
        }
    }
}
公共类示例{
公共静态void main(字符串[]args)引发异常{
对象左=新对象();
对象右=新对象();
LegHolder LegHolder=新的LegHolder();
legHolder.leg=leg.LEFT;
新LeftLegThread(左、右、腿支架).start();
新的RightLegThread(左、右、腿支架).start();
}
}
枚举腿{
左,右
}
阶级议员{
保护腿;
}
类LeftLegThread扩展线程{
私有最终对象左;
私人最终目的权;
私人最终立法权人;
公共LeftLegThread(对象左侧、对象右侧、腿支架){
this.left=左;
这个。右=右;
这个.holder=holder;
}
@凌驾
公开募捐{
试一试{
int i=0;
而(i++<10){
已同步(左){
系统输出打印项次(“左”);
已同步(右){
holder.leg=leg.RIGHT;
对。通知();
}
while(holder.leg!=leg.LEFT)
左。等等();
}
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
类RightLegThread扩展线程{
最后一个物体离开;
最终目的权;
私人最终立法权人;
public RightLegThread(对象左侧、对象右侧、腿支架){
this.left=左;
这个。右=右;
这个.holder=holder;
}
@凌驾
公开募捐{
试一试{
已同步(右){
while(true){
System.out.println(“右”);
已同步(左){
holder.leg=leg.LEFT;
左。notify();
}
while(holder.leg!=leg.RIGHT)
对,等等;
}
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}

也就是说,一个人可能会反复尝试,但这是错误的。我使用普通显示器。请编译并启动。@gstackoverflow-多线程代码的有趣之处在于,您的测试用例可以“工作”,但仍然是完全错误的。您可以重复同一条腿,否则会出现问题,但这并不一定意味着您在测试时会看到这一点。多线程代码在遇到压力时(即在生产中)往往会显示出错误。你确定吗?请用高概率的final static String str=“1”帮助重写遇到压力情况的代码;它是共享的一部分threads@gstackoverflow-是的,我肯定。不幸的是,我不确定是否有“强制失败”的方法,因为您需要人为地延迟java处理通知的方式。这不起作用,因为您正在更改正在同步*和通知)的对象。你应该
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();
        }
    }
}