在过去的几天里,我一直在阅读有关多线程的文章,我遇到了一个使用多线程的简单任务。这是任务:
创建一个模拟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()同步,但程序也无法正常工作。你能告诉我出了什么问题吗?我的错误在哪里?
答案 0 :(得分:2)
每个跑步者增加时间,导致状态不一致。你应该将参赛者与实际比赛分开,这应该是一个单独的班级。
您的问题出现在Racer Runnable的race
方法中,其中每个跑步者递增static time
字段,从而导致意外行为。
答案 1 :(得分:1)
在您的实现中,time
由所有线程共享。因此,如果一个线程增量为,则另一个线程将读取该值,例如:
race()
时间值为0 incrementTime()
将值更改为1 race()
时间值为1 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?
从您的输出中可以清楚地看到另一个线程也增加了时间。可能有另一个线程在您打印获胜者之前增加了时间。要解决您的问题,您必须以这种方式同步incrementTime
和isTheRaceOver
方法,以确保其他线程无法在打印之前增加时间。
但请坚持:同步块不保证更新对另一个称为缓存一致性的线程可见。如果您在一个线程更新变量时没有使用volatile
关键字,则无法保证其他线程会看到它。例如,即使您设置了获胜者,另一个线程仍可能将其视为空。
确保使用volatile关键字或锁(也使用内存屏障)来保证更新对其他线程可见。