伙计所以我的问题是我有3个主题。
1Thread(Bot1)
public class Bot1 implements Runnable {
String name;
public Bot1(String s) throws Exception{
ChatterBotFactory factory = new ChatterBotFactory();
ChatterBot bot1 = factory.create(ChatterBotType.CLEVERBOT);
ChatterBotSession bot1session = bot1.createSession();
name=s;
name=bot1session.think(s);
}
public void run(){
System.out.println("b1: "+name);
}
}
其他人都一样。只有Bot2
和Bot3
的名称。但代码几乎相同。
我需要同时启动这些机器人。而且我只需要显示最快的句子。示例:如果Bot1
显示“Hello”的速度比Bot2
和Bot3
快,那么我需要关闭Bot2
和Bot3
主题。 但我怎么看哪一个更快?我需要关闭哪两个并再次运行我的代码?我希望你理解我并且可以帮助我。谢谢,抱歉我的英语不好。
答案 0 :(得分:2)
您可以使用两个CountDownLatches和一个Semaphore。第一个倒计时锁存器同步线程启动,以便所有线程可以同时启动。第二个倒计时锁存器会在其中一个线程完成时通知您。信号量只允许获胜线程完成,防止竞争条件,其中一些其他线程可能会在您询问哪个线程是赢家时完成。您还需要在Bot类中添加某种已完成的标志,这样主线程就可以先判断哪一个已完成,因为运行方法可能无法及时退出isAlive()
检查工作。
请注意,同时启动的线程仍取决于您的线程调度程序。这是一些示例代码:
创建并启动线程的线程控制器
public void threadController() throws Exception
{
int numWorkers = 20;
List<Worker> workerList = new ArrayList<Worker>(numWorkers);
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(1);
//Semaphore prevents only one thread from completing
//before they are counted
Semaphore pauseForCheck = new Semaphore(1);
for(int i=0; i<numWorkers; i++)
{
Worker worker = new Worker(i, startSignal, doneSignal, pauseForCheck);
Thread thread = new Thread(worker);
//worker has started, but will block on await();
thread.start();
workerList.add(worker);
}
//tell workers they can start
startSignal.countDown();
//wait for one thread to complete.
doneSignal.await();
//Look at all workers and find which one is done
for (int i=0; i< numWorkers; i++)
{
if(workerList.get(i).isCompleted())
{
System.out.printf("Thread %d finished first\n", i);
}
}
//add permits to semaphore so all losing threads can finish
pauseForCheck.release(numWorkers - 1);
}
实际完成工作的工人类
class Worker implements Runnable
{
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final Semaphore pauseForCheck;
private final int id;
private boolean completed = false;
public Worker(int id, CountDownLatch startSignal, CountDownLatch doneSignal, Semaphore pauseForCheck )
{
this.id = id;
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.pauseForCheck = pauseForCheck;
}
public boolean isCompleted()
{
return completed;
}
public void run()
{
try
{
//block until controller counts down the latch
startSignal.await();
//simulate real work
Thread.sleep((long) (Math.random() * 1000));
//try to get the semaphore. Since there is only
//one permit, the first worker to finish gets it,
//and the rest will block.
pauseForCheck.acquire();
}
catch (InterruptedException e)
{
//don't care about this
}
//Use a completed flag instead of Thread.isAlive because
//even though countDown is the last thing in the run method,
//the run method may not have before the time the
//controlling thread can check isAlive status
completed = true;
//tell controller we are finished
doneSignal.countDown();
}
答案 1 :(得分:0)
我会尝试在每个机器人中使用boolean isRunning
,并且在run方法中有while(isRunning)
。然后在第四个线程中,检查所有机器人,看看是否有任何机器人。完成后,将其他机器人的isRunning
设置为false
,然后退出。
答案 2 :(得分:0)
由于你的所有Bot类都有相同的代码,只需要制作一个类Bot并制作三个对象bot1,bot2,bot3。将它们传递给线程构造函数以生成三个线程。
创建一个类变量,例如,boolean accessible = false。还有一个授予读/写锁的共享类。 Bot类的内部运行方法,有这样的东西:
run(){
Lock();
if(accessed){
return;
}
syso("hello");
accessed = true;
Unlock();
}
首先到达的线程将具有锁定并将更改访问的变量,并且在发现该变量设置为true时将返回rest。
答案 3 :(得分:0)
我没有对此进行测试,但希望它可以编译并让您了解一种方法。
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
final class Bot
extends Thread
{
private final CountDownLatch latch;
private final AtomicReference<Bot> winner;
Bot(String name, CountDownLatch latch, AtomicReference<Bot> winner)
{
super(name);
this.latch = latch;
this.winner = winner;
}
@Override
public void run()
{
try {
latch.await();
winner.compareAndSet(null, this);
}
catch (InterruptedException ignore) {
/* This thread was told to stop before completing its work. */
}
}
private static final int BOT_COUNT = 3;
public static void main(String[] argv)
throws Exception
{
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<Bot> ref = new AtomicReference<>();
Set<Bot> losers = new HashSet<>();
for (int i = 0; i < BOT_COUNT; ++i) {
Bot b = new Bot("Bot" + i, latch, ref);
losers.add(b);
b.start();
}
latch.countDown();
for (Bot b : losers)
b.join();
Bot winner = ref.get();
if (winner == null)
System.out.println("No winner.");
else {
losers.remove(winner);
System.out.println("Winner: " + winner.getName());
for (Bot loser : losers)
System.out.println(" Loser: " + loser.getName());
}
}
}
另一个选项可以控制线程的启动,并确保只有一个“胜利”是使用BlockingQueue
。但是,向这个方向发展更加突出了一个更好的方法是使用带有缓存线程的ExecutorService
。
答案 4 :(得分:0)
我在搜索clone
的答案时发现了这个问题。但是,my own question on how to use the result from the fastest thread(由the best answer that I received编写)同样可以很好地应用于这个问题(我原本认为有一个不同的解决方案)所以我认为我会这样做。
IMO这类问题是使用VGR方法的好地方。真的,你不是要立即停止所有线程。相反,您正在尝试使用最快完成的线程的结果,然后忽略后续计算,如果可以,则暂停,但这是次要问题。以下代码取自ExecutorService.invokeAny(),但使用前面提到的import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InvokeAnyThreadController {
public static void main(String[] args) throws Exception {
new InvokeAnyThreadController().threadController();
}
public void threadController() throws Exception {
int numWorkers = 20;
List<Worker> workerList = new ArrayList<>(numWorkers);
for (int i = 0; i < numWorkers; i++) {
Worker worker = new Worker(i);
workerList.add(worker);
}
ExecutorService execSvc = Executors.newFixedThreadPool(numWorkers);
int firstInt = execSvc.invokeAny(workerList);
System.out.println("firstInt=" + firstInt);
}
private static class Worker implements Callable<Integer> {
private final int id;
public Worker(int id) {
this.id = id;
}
@Override
public Integer call() {
return this.id;
}
}
}
方法进行了简化。
invokeAny()
此代码使用@lreeder's answer接口(而不是Callable接口),以便可以返回值。对invokeAny()
的调用保证返回快速计算的值,丢弃所有其他线程。然后next()
调用会尽快停止所有其他线程,但完全有可能其他几个线程也将完成计算,尽管它们的结果将被忽略而不会返回。使用此方法,无需使用较低级别的线程或其他类,如Runnable,Semaphores,CountDownLatches等。