【问题标题】:Other Threads stops when one thread reaches its destination当一个线程到达目的地时其他线程停止
【发布时间】:2015-12-29 17:01:38
【问题描述】:

我目前正在努力理解 Java 的多线程概念。我浏览了一个使用 Tortoise 和 Hare 示例来解释多线程概念的教程,并且在很大程度上理解了视频教程的语法和逻辑。在视频教程的最后,Youtuber 给出了一项涉及将多线程应用到奥林匹克赛道的作业。

利用我从示例中获得的知识,我能够创建 10 个线程(代表运动员)在一个循环中运行,执行 100 次(代表 100 米)。

我的挑战是,当线程调度程序让一名运动员在其他 9 名运动员之前跑到 100 米时,剩余的 9 个线程总是无法完成他们的比赛。在标准赛道中通常不会出现这种情况。事实上,名为 Usain Bolts 的 Thread 首先达到 100,这并不意味着 Yohan Blake 如果当时处于 90m 就应该停止奔跑。

我也有兴趣获取每个线程的距离(注意它们都使用相同的变量),以便我可以使用函数返回每个线程在比赛结束时的位置。

我做了什么(没用): 1)我尝试使用 if else 构造(包含九个“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();

 }
}

【问题讨论】:

  • 数组列表不是线程安全的。我没有看到通常用于并发的同步关键字......我没有展示你如何处理除了 arraylist 之外的比赛,可能使用阻塞队列或安全的东西,或者使用同步的关键工作
  • 如果你想编写灵活健壮的多线程代码,你绝对应该避免直接寻址 Thread 类。使用 Runnable 定义您的任务,并通过 ExecutorService 使它们执行。然后,您将能够控制执行流程和停止条件。网上有很多 ExecutorService 用法的例子。
  • 谢谢。但是有没有办法让这个程序直接使用 Thread 类来做我想做的事情?我想确定多线程中的基本概念。
  • 恐怕您需要发布更多代码才能让我们找到问题所在。是的,可以通过直接使用Thread 类来做到这一点,但首先要注意ArrayList 不是线程安全的警告,并将其包装在线程安全的集合包装器中。
  • List list = Collections.synchronizedList(new ArrayList());

标签: java multithreading netbeans


【解决方案1】:
  1. 我的挑战是……剩下的 9 个线程总是没有完成他们的比赛。

这是由isRaceWon() 方法实现引起的。您在每个跑步者的每一米处检查它。一旦第一个跑步者达到 100 米,break 就会在每个跑步者循环的下一步被调用(每个循环都赢得比赛

顺便说一句,使用 volatile statuc String 作为获胜者的名字是有意义的,以避免 java 的内存模型歧义。

  1. 我也有兴趣获取每个线程的距离...,以便我可以使用函数返回每个线程在比赛结束时的位置。

如果最终目的是获得位置,则创建一个类字段public List&lt;String&gt; finishingOrder = new ArrayList&lt;String&gt;和一个方法finish

private synchronized finish() {
   finishingOrder.add(Thread.currentThread().getName())
}

在“运行”循环之后调用它

不要忘记为main 中的所有运行线程调用join()。之后,finishingOrder 将包含按完成顺序排列的名称。

【讨论】:

    【解决方案2】:

    只要共享的winner 字段设置为非空(即有人获胜.):

    else if (HundredMetersTrackRules.winner!=null) {
       isRaceWon=true;
    }
    

    这反过来会导致race() 中的循环因Runnable 的每个实例而中断。 run() 方法退出,终止线程。

    这个问题只是一个逻辑错误,并不是真正特定于线程。但是,正如其他发帖人所提到的,您还可以在此代码中采用一些线程最佳实践,例如将volatile 用于线程共享的字段。

    【讨论】:

      【解决方案3】:

      实际上,对于 Race,您需要立即启动所有线程,然后只启动它的 Race。 CountDownLatch 更适合实现或编写竞赛程序。

      我们也可以通过许多其他方式编写 Race 程序而不使用 CountDownLatch。 如果我们需要使用基/低级来实现,那么我们可以在同步块中使用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);
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-05
        相关资源
        最近更新 更多