Question

Folks so my problem is that I have 3 Threads.

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);
  }
}

And the others are same. Only names are Bot2 and Bot3. But the code is almost same. I need to start these bots at the same time. And I need to display only the sentence that is fastest. Example: if Bot1 displayed "Hello" faster than Bot2 and Bot3, then I need to close the Bot2 and Bot3 thread. But how do I see which one was faster? And which two do I need to close and run my code again? I hope You understand me and can help me. Thank you and sorry for my bad English.

Was it helpful?

Solution 2

I would try having a boolean isRunning in each bot and in the run method have a while(isRunning). Then in a fourth thread, check through all of the bots and see if any are done. If one is done, set the isRunning of the others bots to false and they should exit.

OTHER TIPS

You can use two CountDownLatches and one Semaphore. The first countdown latch synchronizes the thread starts so that all threads are available to start at the same time. The second countdown latch notifies you when one of the threads is finished. The semaphore allows only the winning thread to complete, preventing a race condition where some other threads might finish while you asking which thread is the winner. You'll also need to add some sort of completed flag to your Bot classes so the main thread can tell which one completed first, because the run method may not exit in time for isAlive() checks work.

Note that thread starting at the same time still depends on your thread scheduler. Here's some sample code:

Thread Controller which creates and starts the threads

  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);
 }

Worker class that actually does the work

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();
   }

Since your all Bot classes have same code, make just a single class Bot and make three objects bot1, bot2, bot3. Pass them to threads constructor to make three threads.

Make a class variable say, boolean accessed = false. Also have a shared class granting Read/Write Lock. Inside run method of Bot class , have something like this :

run(){
Lock();
if(accessed){
return;
}
syso("hello");
accessed = true;

Unlock();
}

The thread which reaches first will have the lock and will change the variable accessed and rest would return on finding that the variable is set to true.

I didn't test this, but hopefully it compiles and gives you an idea about one way to do this.

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());
    }
  }

}

Another option that would both control the starting of the threads, and ensure that only one "wins" is to use a BlockingQueue. However, moving in that direction highlights even more that a better approach would be to use an ExecutorService with cached threads.

I found this question while searching for an answer to my own question on how to use the result from the fastest thread. But, the best answer that I received (written by VGR) can be equally well applied to this question as well (which I originally thought had a different solution) so I thought that I would do that.

IMO this type of problem is a great place to use the ExecutorService.invokeAny() method. Really, you aren't trying immediately halt all threads. Rather, you are trying to use the result of the thread that completed the fastest, and then are just ignoring subsequent computations, halting if you can, but that is a secondary concern. The following code was taken from @lreeder's answer, but it is simplified using the previously mentioned invokedAny() method.

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;
    }
  }
}

This code uses the Callable interface (instead of the Runnable interface) so that a value can be returned. The call to invokeAny() is guaranteed to return the value of the fast computation, discarding all other threads. The invokeAny() call then proceeds to halt all other threads as soon as it can, but it's entirely possible that several other threads will finish computing as well, although their results will be ignored and not returned. Using this method, there is no need to use lower level threads, or other classes like Semaphores, CountDownLatches, FutureTasks, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top