线程:忙等待 - 空循环

时间:2014-01-23 11:08:57

标签: java eclipse multithreading busy-waiting

在我们上大学的课程中,我们了解了Threads并使用“忙碌等待”方法获取Car等待TrafficLight的示例。对于此任务,我们构建了三个类:

  • TrafficLight (implements Runnable)
  • Car (implements Runnable)
  • Main

在我们的Main课程中,我们开始了两个Thread,一个是Car,另一个是TrafficLightCar具有布尔属性hasToWait。此类中的run()方法的工作方式是,只要while,它就可以通过hasToWait == true循环工作。要更改此设置,我们在notifyCar()类中使用了Car方法,该方法由TrafficLight使用。 run()中的TrafficLight方法会运行Thread.sleep()来模拟等待的特定时间。

我教授的一切都很好,但最终我遇到了严重的问题。只要while类中的Car循环为空。当我输入System.out.println() - 为空时,它就可以了。但是如果Syso为空,则结果是不显示Run方法的文本。 当Thread.sleep()中的TrafficLight0时,它也会正常工作。比它使用空while循环。

这是我的代码:

Car.java:

package trafficlight;

public class Car implements Runnable {

    private boolean hasToWait = true;

    public void run() {
        this.crossTrafficLight();
    }

    public void crossTrafficLight() {
        while(hasToWait){ for(int i = 0; i<20; i++){System.out.println("123");}} // Busy waiting
        System.out.println("Auto fährt über Ampel");
    }

    public void notifyCar() {
        this.hasToWait = false;
        System.out.println("Test");
    }
}

TrafficLight.java:

package trafficlight;

public class TrafficLight implements Runnable {
    private Car car;

    public TrafficLight(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.car.notifyCar();
    }
}

Main.java:

package trafficlight;

public class Main {

    public static void main(String[] args){
        Car car = new Car();
        TrafficLight tl = new TrafficLight(car);

        new Thread(car).start();
        new Thread(tl).start();
    }

}

问题出在哪里?为什么它适用于我的教授而不是我的电脑?我使用JRE 1.7

在Eclipse Juno中获得了代码1:1

2 个答案:

答案 0 :(得分:3)

除了this other answer中所说的所有内容(在该答案中只替换hasToWait代表finished),代码在添加println时开始工作的原因如下:

  • println synchronized 方法;
  • 你在两个线程中调用它;
  • 这会在两个线程之间创建发生之前的关系;
  • 因此,对子线程可以看到对布尔标志的写入。

你可以说它主要是开始工作:你正在捎带println中正在进行的同步。

答案 1 :(得分:1)

代码的真正问题是实例字段hasToWait。该字段由两个线程使用。汽车线程读取值,交通灯线程在一段时间后更新该值。

必须以某种方式同步对此字段的访问。

有两种方法可以做到这一点:

  1. 使用synchronized关键字。通过在所有位置使用同步块,在其中读取或写入,或者 - 更好 - 编写同步的getter和同步的setter,然后使用Car类中的getter和setter。

  2. 使用volatile关键字。只需声明您的字段为volatile。这个关键字确实存在于这种情况下。有关volatile的更多信息,请参阅Oracle's Java Tutorials

  3. 在阅读了有关原子访问的文章后(参见上面的链接),应该清楚的是选项2(声明volatile)是更好的选择 - 对于这个用例。

    现在您的计算机和教授的计算机之间存在差异:只要您使用的是单核处理器,就会看到其他线程中的实例字段的更新,就像它们已经同步一样< / em>,因为CPU不必在其他内核的缓存区域中同步这些值。如果使用多核处理器,则JVM能够在多个核上运行线程。这意味着,这些内核必须同步值,并且易失性机制正是为此而设计的。