当一个线程到达目的地时,其他线程停止



我目前正在努力理解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();
 }
}
  1. 我的挑战是……剩下的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);
      }
    }
    

    相关内容

    • 没有找到相关文章

    最新更新