当一个线程到达目标

时间:2015-10-01 15:09:37

标签: java multithreading netbeans

我目前正致力于理解多线程的Java概念。我经历了一个使用Tortoise和Hare示例的教程来解释多线程的概念,并且在很大程度上我理解了视频教程的语法和逻辑。在视频教程的最后,Youtuber做了一项任务,涉及将多线程应用于奥运赛道。

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

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

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

我做了什么(不起作用):  1)我试图使用if else结构(包含9个“else”)  statement)将每个执行线程的距离分配给新的整数变量。 (使用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();

 }
}

3 个答案:

答案 0 :(得分:0)

  1.   

    我的挑战是......其余9个线程总是无法完成比赛。

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

    顺便说一句,将volatile statuc String用于获胜者名称是有意义的,以避免java的内存模型模糊。

    1.   

      我也有兴趣获得每个线程的距离......这样我就可以使用函数在比赛结束时返回每个线程的位置。

    2. 如果最终目标是获得排名,请创建一个类字段public List<String> finishingOrder = new ArrayList<String>和一个方法finish

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

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

      不要忘记为join()中的所有参赛者线程致电main。之后,finishingOrder将按顺序包含名称。

答案 1 :(得分:0)

以下代码段导致isRaceWon只要共享HundredMetersTrackRules字段设置为非空,就会为每个 winner实例返回true (即有人获胜。):

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

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

问题只是一个逻辑错误,并不是特定于线程。但是,正如其他海报所提到的那样,您可以在此代码中采用一些线程最佳实践,例如对线程共享的字段使用volatile

答案 2 :(得分:0)

实际上,对于Race,您需要一次启动所有线程,然后仅启动其Race。 CountDownLatch是实施或编写Race Program的更好选择。

还有许多其他方法,我们无需编写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);
  }
}