我目前正在努力理解Java的多线程概念。我看了一个教程,用乌龟和兔子的例子来解释多线程的概念,在很大程度上我理解了视频教程的语法和逻辑。在视频教程的最后,Youtuber给出了一个作业,涉及到将多线程应用于奥林匹克赛道。
使用我从示例中获得的知识,我能够创建10个线程(代表运动员),它们在一个循环中运行,执行100次(代表100米)。
我的挑战是,当线程调度程序让一个运动员在其他9个运动员之前到达100米时,剩下的9个线程总是没有完成他们的比赛。在标准赛道上通常不会出现这种情况。一个叫尤塞恩·博尔特(Usain Bolts)的Thread先跑到100米,这并不意味着约翰·布莱克(Yohan Blake)在那个时候跑到90米时就应该停止跑步。
我也对获得每个线程的距离(注意它们都使用相同的变量)感兴趣,这样我就可以使用函数在比赛结束时返回每个线程的位置。
我所做的(没有工作):1)我尝试使用if else结构(包含9个"else")语句)将每个执行线程的距离赋值给一个新的整数变量。(使用thread . currentthread (). getname()属性和每个线程的名称),但这对我来说并不奏效。这是一个尝试,给运动员单独的位置,利用他们的距离,但没有对9名运动员没有完成比赛。2)我也尝试过在运行时使用ArrayList来填充距离,但由于一些奇怪的原因,每次它想要添加另一个距离时,它仍然会覆盖距离。
下面是我的代码:
package olympics100meters;
import java.util.ArrayList;
public class HundredMetersTrackRules implements Runnable {
public static String winner;
public void race() {
for (int distance=1;distance<=50;distance++) {
System.out.println("Distance covered by "+Thread.currentThread ().getName ()+" is "+distance+" meters.");
boolean isRaceWon=this.isRaceWon(distance);
if (isRaceWon) {
ArrayList<Integer> numbers = new ArrayList();
numbers.add(distance);
System.out.println("testing..."+numbers);
break;
}
}
}
private boolean isRaceWon(int totalDistanceCovered) {
boolean isRaceWon=false;
if ((HundredMetersTrackRules.winner==null)&& (totalDistanceCovered==50)) {
String winnerName=Thread.currentThread().getName();
HundredMetersTrackRules.winner=winnerName;
System.out.println("The winner is "+HundredMetersTrackRules.winner);
isRaceWon=true;
}
else if (HundredMetersTrackRules.winner==null) {
isRaceWon=false;
}
else if (HundredMetersTrackRules.winner!=null) {
isRaceWon=true;
}
return isRaceWon;
}
public void run() {
this.race();
}
}
这是我的主要方法(我把它减少到5个运动员,直到我理清问题):
public class Olympics100Meters {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
HundredMetersTrackRules racer=new HundredMetersTrackRules();
Thread UsainBoltThread=new Thread(racer,"UsainBolt");
Thread TysonGayThread=new Thread (racer,"TysonGay");
Thread AsafaPowellThread=new Thread(racer,"AsafaPowell");
Thread YohanBlakeThread=new Thread (racer,"YohanBlake");
Thread JustinGatlinThread=new Thread (racer,"JustinGatlin");
UsainBoltThread.start();
TysonGayThread.start();
AsafaPowellThread.start();
YohanBlakeThread.start();
JustinGatlinThread.start();
}
}
-
我的挑战是……剩下的9个线程总是不能完成它们的竞争。
这是由isRaceWon()
方法实现引起的。你在每个跑步者的每一米检查它。当第一个跑到100米时,break
在每个跑圈的下一步被调用(每个跑圈获胜)
btw,使用volatile statuc String
作为获胜者的名字是有意义的,以避免java的内存模型歧义。
-
我也对获得距离感兴趣…,这样我就可以使用一个函数来返回每个线程在比赛结束时的位置。
如果最终目标是获得位置,创建一个类字段public List<String> finishingOrder = new ArrayList<String>
和一个方法finish
private synchronized finish() {
finishingOrder.add(Thread.currentThread().getName())
}
并在"run"循环之后调用
不要忘记为main
中的所有运行线程调用join()
。之后,finishingOrder
将按结束顺序包含名称。
下面的代码片段导致isRaceWon
对每个 HundredMetersTrackRules
实例返回true,只要共享的winner
字段被设置为非空(即有人获胜):
else if (HundredMetersTrackRules.winner!=null) {
isRaceWon=true;
}
这会导致race()
中的循环在Runnable
的每个实例中都中断。run()
方法退出,终止线程。
这个问题只是一个逻辑错误,并不是真正特定于线程。但是,正如其他发帖者所提到的,在这段代码中也可以采用一些线程最佳实践,例如使用volatile
来处理线程共享的字段。
实际上,对于Race,您需要一次启动所有线程,然后只启动它的Race。CountDownLatch
是更好的实现或编写比赛程序。
CountDownLatch
的情况下,我们还可以用许多其他方法编写Race程序。如果我们需要使用基/低电平来实现,那么我们可以在同步块中使用volatile
布尔标志和计数器变量,或者使用wait()
和notifyAll()
逻辑,等等,
在程序的for循环中引入了一些时间延迟。只有你才能感受到这种体验。为什么?因为你没有一次启动所有的线程。
希望你在练习初始/基础水平,所以我做了一些改变,只是为了更好地理解和解决你所有的问题。
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
class HundredMetersTrackRules implements Runnable {
public static Main main;
HundredMetersTrackRules(Main main){
this.main=main;
}
public static String winner;
public void race() {
try{
System.out.println(Thread.currentThread().getName()+" Waiting for others...");
while(!Main.start){
Thread.sleep(3);
}
for (int distance=1;distance<=50;distance++) {
System.out.println("Distance covered by "+Thread.currentThread().getName()+" is "+distance+" meters.");
Thread.sleep(1000);
}
synchronized(main){
Main.finish--;
}
Main.places.add(Thread.currentThread().getName());
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
public void run() {
this.race();
}
}
public class Main
{
public static volatile boolean start = false;
public static int finish = 5;
final static List<String> places =
Collections.synchronizedList(new ArrayList<String>());
public static void main(String[] args) {
HundredMetersTrackRules racer=new HundredMetersTrackRules(new Main());
Thread UsainBoltThread=new Thread(racer,"UsainBolt");
Thread TysonGayThread=new Thread (racer,"TysonGay");
Thread AsafaPowellThread=new Thread(racer,"AsafaPowell");
Thread YohanBlakeThread=new Thread (racer,"YohanBlake");
Thread JustinGatlinThread=new Thread (racer,"JustinGatlin");
UsainBoltThread.start();
TysonGayThread.start();
AsafaPowellThread.start();
YohanBlakeThread.start();
JustinGatlinThread.start();
Main.start=true;
while(Main.finish!=0){
try{
Thread.sleep(100);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
System.out.println("The winner is "+places.get(0));
System.out.println("All Places :"+places);
}
}