Java 如何在多线程程序中使用CountDownLatch
我是Java的初学者,正在尝试创建一个程序,其中两条“船”通过多线程在屏幕上相互竞赛。我让线程部分与两条线平行地从屏幕上下来 但是我希望线程在命令的同时启动,所以我找到了CountDownLatch类。我真的不太理解它,但我尝试使用它,仍然使用闩锁,并让线程等待(),直到调用Java 如何在多线程程序中使用CountDownLatch,java,multithreading,synchronization,Java,Multithreading,Synchronization,我是Java的初学者,正在尝试创建一个程序,其中两条“船”通过多线程在屏幕上相互竞赛。我让线程部分与两条线平行地从屏幕上下来 但是我希望线程在命令的同时启动,所以我找到了CountDownLatch类。我真的不太理解它,但我尝试使用它,仍然使用闩锁,并让线程等待(),直到调用latch.countDown()。这一切都很好,但我想知道哪个线程先完成,所以我在main方法中使用了计时器和if语句来确定哪个线程/船更快 然而,我的两个问题是a。出于某种原因,所有内容都会打印两次,就好像它在两次执行r
latch.countDown()
。这一切都很好,但我想知道哪个线程先完成,所以我在main方法中使用了计时器和if
语句来确定哪个线程/船更快
然而,我的两个问题是a。出于某种原因,所有内容都会打印两次,就好像它在两次执行run()操作一样。if语句总是直接转到else,因为它认为两个记录的时间都不大于另一个。我有一种感觉,这一切都是因为我把倒计时锁搞得一团糟,但我只是没有经验去弄清楚
主要方法:
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");
}
}
具有线程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");
}
}
}
使用synchronized方法初始化以获取完成时间:
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");
}
}
在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();
}
您不需要赛艇手(或2队)内的线程。在Regatta类中创建的线程足以调用Rower(和Team2)中的“run”方法
另外,作为旁注:您根本不需要Team2类。。。您应该能够通过初始化两个Rower对象来比赛两条不同的船
Rower r1 = new Rower(latch, roweronename, timed);
// Changed from Team2 to Rower
Rower r2 = new Rower(latch, rowertwoname, timed);
如果两条船的功能不同,比如一条船的推进方式不同于另一条船(划船vs帆船,vs摩托艇,等等),那么您只需要拥有两个不同的船类。在您的情况下,它们看起来基本相同(几乎是复制粘贴的)。哦,我的上帝,谢谢!但是关于第二部分,另一个类的原因是因为我需要其中一个线程打印第一个线程之外的几个空格。第一个线程正在打印“|”,而另一个线程正在打印“--------------------------|”。如果您能告诉我一个更好的方法,我们将不胜感激。(破折号是空格)有无数种方法可以像您建议的那样打印自定义值,但一种方法是将所需的值发送到构造函数参数中,并将其存储在类中<代码>字符串rowereonetail=“|”
划船机r1=新划船机(闩锁、划船机名称、定时、划船机尾)
然后更新Rower类构造函数以获取tail参数:Rower(CountDownLatch闩锁,字符串名称,Q timed,字符串tail){
在本地设置:this.tail=tail;
然后更新print方法:System.out.println(tail);
很高兴它对您有用!请随意接受这一“正确答案”
// These are all you need to get the boats to race!
new Thread(r1).start();
new Thread(r2).start();
Rower r1 = new Rower(latch, roweronename, timed);
// Changed from Team2 to Rower
Rower r2 = new Rower(latch, rowertwoname, timed);