为什么同步在此代码中无法正常工作?

时间:2016-09-25 19:14:19

标签: java multithreading synchronization

在过去的几天里,我一直在阅读有关多线程的文章,我遇到了一个使用多线程的简单任务。这是任务:

创建一个模拟50米跑步比赛的应用程序(在我的代码中它们是10,无关紧要)。跑步者的数量应为5,您应该为每个跑步者线程命名。打印获胜者。所有其他线程也应该完成比赛。打印每个跑步者完成比赛所花费的时间并突出显示获胜者的时间。

这是我写的代码:

public class Racer implements Runnable {
    public static String winner;
    public static int time = 0;

    public void incrementTime() {
        synchronized (Racer.class) {
            time++;
        }
    }
    public void race() {
        for (int distance = 1; distance <= 10; distance++) {
            incrementTime();
            System.out.println("Distance covered by " + Thread.currentThread().getName() + " is " + distance + " meters.");
            boolean finalDest = this.isTheRaceOver(distance);
            if (finalDest) {
                break;
            }
        }
    }
    private boolean isTheRaceOver(int finalDistance) {
        boolean isRaceOver = false;
        if (Racer.winner == null && finalDistance == 10) {
            String winnerName = Thread.currentThread().getName();
            Racer.winner = winnerName;
            System.out.println("The winner is : " + Racer.winner + " with time " + time);
            isRaceOver = true;
        } else if (Racer.winner == null) {
            isRaceOver = false;
        } else if (finalDistance != 10) {
            isRaceOver = false;
        } else if (finalDistance == 10) {
            System.out.println(Thread.currentThread().getName() + " is with time " + time);
        }
        return isRaceOver;
    }
    @Override
    public void run() {
        this.race();
    }
}

public class RacerDemo {
    public static void main(String[] args) {
        Racer racer = new Racer();
        Thread a = new Thread(racer, "A");
        Thread b = new Thread(racer, "B");
        Thread c = new Thread(racer, "C");
        Thread d = new Thread(racer, "D");
        Thread e = new Thread(racer, "E");
        a.start();
        b.start();
        c.start();
        d.start();
        e.start();
    }
}

一个输出是:

Distance covered by A is 1 meters. 
Distance covered by C is 1 meters. 
Distance covered by C is 2 meters. 
Distance covered by C is 3 meters.
Distance covered by C is 4 meters.
Distance covered by C is 5 meters.
Distance covered by C is 6 meters.
Distance covered by C is 7 meters.
Distance covered by C is 8 meters.
Distance covered by C is 9 meters.
Distance covered by C is 10 meters.
The winner is : C with time 12  // should be 11 ?
Distance covered by B is 1 meters.
Distance covered by B is 2 meters. 
...... and so on

困扰我的是当它打印每个赛车手(线程)所占用的时间来覆盖距离时,它没有显示正确的时间。我使incrementTime()同步,但程序也无法正常工作。你能告诉我出了什么问题吗?我的错误在哪里?

4 个答案:

答案 0 :(得分:2)

每个跑步者增加时间,导致状态不一致。你应该将参赛者与实际比赛分开,这应该是一个单独的班级。

您的问题出现在Racer Runnable的race方法中,其中每个跑步者递增static time字段,从而导致意外行为。

答案 1 :(得分:1)

在您的实现中,time由所有线程共享。因此,如果一个线程增量为,则另一个线程将读取该值,例如:

  • 线程1输入race()时间值为0
  • 主题1调用incrementTime()将值更改为1
  • 线程2输入race()时间值为1
  • 线程2调用incrementTime()将值更改为2

这会使time变量处于不一致状态。为避免这种情况,您可以尝试在time方法中对race()进行声明,以便每个线程都有自己的时间。

答案 2 :(得分:0)

每个跑步者增加时间并且增量时间方法只有锁定。 Runner C完成比赛并调用isRaceOver方法。当c将获得11的时间时,线程b运行竞争方法,潜入并增加时间1.结果,c获得12的时间并错误地打印出时间。如果您的目的是让所有参赛者能够增加时间,您必须确保一次只有1个线程正在竞赛或IsTheRaceOver。

答案 3 :(得分:0)

由于您同步了一个默认为原子的整数,因此在没有synchronized块的情况下会得到相同的结果。同步关键字是不必要的,因此根本没有同步。

  

A所涵盖的距离为1米   C所覆盖的距离为1米   C所覆盖的距离为2米   ...
  获胜者是:C时间12 //应该是11?

从您的输出中可以清楚地看到另一个线程也增加了时间。可能有另一个线程在您打印获胜者之前增加了时间。要解决您的问题,您必须以这种方式同步incrementTimeisTheRaceOver方法,以确保其他线程无法在打印之前增加时间。

但请坚持:同步块不保证更新对另一个称为缓存一致性的线程可见。如果您在一个线程更新变量时没有使用volatile关键字,则无法保证其他线程会看到它。例如,即使您设置了获胜者,另一个线程仍可能将其视为空。

确保使用volatile关键字或锁(也使用内存屏障)来保证更新对其他线程可见。