【问题标题】:How to use CountDownLatch in a multithreading program如何在多线程程序中使用 CountDownLatch
【发布时间】:2017-06-09 18:32:32
【问题描述】:

我是 Java 的初学者,我正在尝试创建一个程序,其中两个“船”使用多线程在屏幕上相互竞速。我让线程部分与从屏幕向下平行的两条线一起工作。

但我希望线程在命令的同时启动,所以我找到了 CountDownLatch 类。我真的不太了解它,但我尝试使用它仍然使用闩锁,并让线程等待(),直到我调用latch.countDown()。这一切都很好,但我想知道哪个线程先完成,所以我在 main 方法中使用了一个计时器和一个if 语句来确定哪个线程/“船”更快。

但是我的两个问题是:出于某种原因,所有内容都会打印两次,就好像它正在执行 run() 两次,并且 b. if 语句总是直接指向 else,因为它认为任何一个记录的时间都不会大于另一个。我有一种感觉,这一切都是由于我对 CountDownLatch 造成的一些混乱,但我只是没有经验来解决它。

主要方法:

package practice;

import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.*;

public class Regatta {
    public static void main(String[] args) {
        Q timed = new Q();
        CountDownLatch latch = new CountDownLatch(0);
        Thread t1 = Thread.currentThread();
        Scanner scan = new Scanner(System.in);
        System.out.println("What team is rower 1 on?");
        String roweronename = scan.nextLine();
        System.out.println("What team is rower 2 on?");
        String rowertwoname = scan.nextLine();

        Rower r1 = new Rower(latch, roweronename, timed);
        Team2 r2 = new Team2(latch, rowertwoname, timed);

        try {
            System.out.println("ATTENTION");
            t1.sleep(1000);
            System.out.println("READY");
            t1.sleep(1000);
            System.out.println("ROW!");
            System.out.println();
            System.out.println(roweronename.toUpperCase() + "             " + rowertwoname.toUpperCase());
            System.out.println("--------------------------------------------");
            new Thread(r1).start();
            new Thread(r2).start();
            latch.countDown();

        } catch (InterruptedException e) {
            System.out.println("There was an error. Don't click out of the program.");
        } catch (Exception e) {
            System.out.println("There was another error");
        }
        try {
            r1.t.join();
            r2.t.join();
        } catch (InterruptedException e) {
            System.out.println("interruption error occurred");
        }
        double finalTimeOne = r1.finalTime;
        double finalTimeTwo = r2.finalTime;

        if (finalTimeOne < finalTimeTwo) {
            System.out.println(roweronename.toUpperCase() + " HAS WON THE RACE!");
        } else if (finalTimeTwo < finalTimeOne) {
            System.out.println(rowertwoname.toUpperCase() + " HAS WON THE RACE!");
        } else
            System.out.println("Nobody won");
    }
}

带有thread1的子类:

package practice;

import java.util.concurrent.CountDownLatch;

public class Rower implements Runnable {
    int meters = 2000;
    double startTime, endTime, finalTime;
    Thread t;
    String name;
    CountDownLatch latch;
    Q timed;
    public Rower(CountDownLatch latch, String name, Q timed) {
        this.timed=timed;
        this.latch = latch;
        this.name = name;
        t = new Thread(this, name);
        t.start();
        System.out.println();   
    }

    public void run() {
        try {
            latch.await();
            double startTime = System.nanoTime();
            for (int i = 20; i >= 0; i--) {
                System.out.println("|");// each - is 10 meters
                Thread.sleep(100);
        }
            double endTime = System.nanoTime();
            double finalTime = endTime - startTime;
            timed.getTime(finalTime,name);

        } catch (InterruptedException e) {
            System.out.println("GET OUT THE WAY!");
            System.out.println("race postponed to tommorow");
        }

    }

}

线程 2 的子类:

package practice;
import java.util.concurrent.CountDownLatch;

public class Team2 implements Runnable {
    Q timed=new Q();
    int meters = 2000;
    double startTime,endTime,finalTime;
    Thread t;
    String name;
    CountDownLatch latch;
    public Team2(CountDownLatch latch,String name, Q timed) {
        this.timed=timed;
        this.latch=latch;
        this.name = name;
        t = new Thread(this, name);
        t.start();
        System.out.println();
    }

    public void run() {
        try {

            latch.await();
            double startTime=System.nanoTime();

            for (int i = 20; i >= 0; i--) {
                int j=20-i;
                System.out.println("                  |");// each | is 10 meters
                Thread.sleep(100);
            }
            double endTime=System.nanoTime();
            double finalTime=endTime-startTime;

                timed.getTime(finalTime, name);


        } catch (InterruptedException e) {
            System.out.println("GET OUT THE WAY!");
            System.out.println("race postponed to tommorow");
        }

    }

}

使用同步方法获取完成时间的类:

  package practice;    
   public class Q {
    double finalTime;
    String name;
    synchronized void getTime(double finalTime, String name){
        this.finalTime=finalTime;
        this.name=name;
        System.out.println("Time of team "+this.name+": "+this.finalTime);//prints twice?
        System.out.println("vinay");
    }
}

【问题讨论】:

    标签: java multithreading synchronization


    【解决方案1】:

    在您的 Rower(和 Team2)类构造函数中,您正在初始化一个全新的线程并启动它:

    public Rower(CountDownLatch latch, String name, Q timed) {
        this.timed=timed;
        this.latch = latch;
        this.name = name;
        //vvvvvvvv THIS IS THE PROBLEM vvvvvvvv//
        t = new Thread(this, name);
        t.start();
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
        System.out.println();   
    }
    

    您不需要在 Rower(或 Team2)中使用 Thread。在您的 Regatta 类中创建的线程足以调用 Rower(和 Team2)中的“run”方法

    // These are all you need to get the boats to race!
    new Thread(r1).start();
    new Thread(r2).start();
    

    另外,作为旁注:您根本不需要 Team2 类...您应该能够通过初始化两个 Rower 对象来比赛两艘不同的船。

    Rower r1 = new Rower(latch, roweronename, timed);
    // Changed from Team2 to Rower
    Rower r2 = new Rower(latch, rowertwoname, timed);
    

    如果两艘船具有不同的功能,您只需要拥有两种不同的船类,例如一艘船的推进方式与另一艘船不同(划船与帆船、摩托艇等)。在您的情况下,它们看起来基本相同(几乎是复制粘贴的)。

    【讨论】:

    • 天哪,谢谢!但是关于第二部分,另一个类的原因是因为我需要一个线程打印距离第一个线程几个空格的线程。第一个线程正在打印“|”而另一个正在打印“ ----------------------- |”。如果您能说出更好的方法,将不胜感激。(破折号是空格)
    • 有无数种方法可以像您建议的那样打印自定义值,但一种方法是将所需的值发送到构造函数参数中,并将其存储在类中。 String rowereonetail = "|"; Rower r1 = new Rower(latch, roweronename, timed, roweronetail); 然后更新 Rower 类构造函数,取尾部参数:Rower(CountDownLatch latch, String name, Q timed, String tail) { 本地设置:this.tail = tail; 然后更新打印方法:System.out.println(tail);
    • 很高兴它为您工作!随意接受这是“正确答案”
    猜你喜欢
    • 2023-03-21
    • 2015-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多