Casper Flintrup
Casper Flintrup

Reputation: 35

Threads waiting for each other

I am trying to make my threads follow each other like its a race and a want the threads to wait for each other. Like:

DUCK is on his 1 lap
PIGGY is on his 1 lap
ELEFANT is on his 1 lap
STAR is on his 1 lap

DUCK is on his 2 lap
PIGGY is on his 2 lap
ELEFANT is on his 2 lap
STAR is on his 2 lap

and so on..

public class ExThread implements Runnable {

    String name;
    Random r = new Random();
    int count;
    int sleepTimer;

    public ExThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
       try {
            for(int i = 0; i < 10; i++) {
                count++;
                sleepTimer = r.nextInt(1000)+1;
                Thread.sleep(sleepTimer);
                System.out.println(
                   name + " Starts after "+sleepTimer+" milliseconds break");
                System.out.println(
                   name+" is on his "+count+" lap");

            }
            System.out.println(name+" completes the race!!!");
        }
        catch (Exception e){}
    }

public class ThreadsEx {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new ExThread("STAR"));
        Thread t2 = new Thread(new ExThread("ELEFANT"));
        Thread t3 = new Thread(new ExThread("PIGGY"));
        Thread t4 = new Thread(new ExThread("DUCK"));
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

Upvotes: 1

Views: 1242

Answers (5)

Tadija Bagarić
Tadija Bagarić

Reputation: 2701

You could use join.

for(i = 0; i < threads.length; i++){
    threads[i].join();
}

Join will block current thread (Main thread in your case I presume). When the for loop finishes all threads will be done with their work.

In your case, you could make each thread do a single lap instead of 10.

for(j = 0; j < numberOfLaps; j++){
    for(i = 0; i < threads.length; i++){
        threads[i].join();
    }
}

Upvotes: 0

Aubin
Aubin

Reputation: 14853

You have to use java.util.concurrent, like this :

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class RendezVous extends Thread {

   private final CountDownLatch _start;
   private final CyclicBarrier  _rdv;
   private final CountDownLatch _stop;

   public RendezVous(
      String         name,
      CountDownLatch start,
      CyclicBarrier  rdv,
      CountDownLatch stop    )
   {
      super( name );
      _start = start;
      _rdv   = rdv;
      _stop  = stop;
      start();
   }

   @Override
   public void run() {
      final Random rnd = new Random( System.currentTimeMillis());
      try {
         System.out.println( getName() + " is started" );
         _start.countDown();
         System.out.println( getName() + " waits for others" );
         _start.await();
         System.out.println( getName() + " is running" );
         for(int count = 0, i = 0; i < 10; ++i, ++count ) {
            final long sleepTimer = rnd.nextInt( 1000 ) + 1;
            sleep( sleepTimer );
            System.out.println( getName() +" is on his " + count + " lap" );
            _rdv.await();
         }
         _stop.countDown();
         _stop.await();
         System.out.println( getName() + " completes the race" );
      }
      catch( final Exception e ) {
         e.printStackTrace();
      }
   }

   public static void main(String[] args) {
      final CountDownLatch start = new CountDownLatch( 4 );
      final CyclicBarrier  rdv   = new CyclicBarrier( 4 );
      final CountDownLatch stop  = new CountDownLatch( 4 );
      new RendezVous( "STAR"   , start, rdv, stop );
      new RendezVous( "ELEFANT", start, rdv, stop );
      new RendezVous( "PIGGY"  , start, rdv, stop );
      new RendezVous( "DUCK"   , start, rdv, stop );
   }
}

Execution log:

DUCK is started
STAR is started
DUCK waits for others
PIGGY is started
ELEFANT is started
PIGGY waits for others
STAR waits for others
PIGGY is running
STAR is running
ELEFANT waits for others
DUCK is running
ELEFANT is running
STAR is on his 0 lap
PIGGY is on his 0 lap
DUCK is on his 0 lap
ELEFANT is on his 0 lap
DUCK is on his 1 lap
STAR is on his 1 lap
ELEFANT is on his 1 lap
PIGGY is on his 1 lap
STAR is on his 2 lap
ELEFANT is on his 2 lap
PIGGY is on his 2 lap
DUCK is on his 2 lap
STAR is on his 3 lap
PIGGY is on his 3 lap
ELEFANT is on his 3 lap
DUCK is on his 3 lap
DUCK is on his 4 lap
PIGGY is on his 4 lap
ELEFANT is on his 4 lap
STAR is on his 4 lap
STAR is on his 5 lap
PIGGY is on his 5 lap
ELEFANT is on his 5 lap
DUCK is on his 5 lap
STAR is on his 6 lap
DUCK is on his 6 lap
PIGGY is on his 6 lap
ELEFANT is on his 6 lap
PIGGY is on his 7 lap
ELEFANT is on his 7 lap
STAR is on his 7 lap
DUCK is on his 7 lap
ELEFANT is on his 8 lap
DUCK is on his 8 lap
PIGGY is on his 8 lap
STAR is on his 8 lap
STAR is on his 9 lap
ELEFANT is on his 9 lap
DUCK is on his 9 lap
PIGGY is on his 9 lap
DUCK completes the race
PIGGY completes the race
ELEFANT completes the race
STAR completes the race

Upvotes: 0

uzr
uzr

Reputation: 1210

I assume the rules are:

  • All threads must be on the same lap
  • Threads can finish their lap in any order but cannot progress to the next lap before all threads have finished that lap.

These rules above require some form of synchronization between the threads and there are a few synchronization options available in Java

An initial proposal would be to use a value that all threads have access to so that they can communicate their progress and know if they can progress to the next lap or not and keep track of each others progress.

Some general notes to your implementation

  • System.out.println does not guarantee the order in which messages gets printed out to the console in multithreaded applications. They can arrive in a different order to the console than that method gets called in the code.
  • Thread.sleep does not guarantee an exact sleep time.

Upvotes: 1

Mark Jeronimus
Mark Jeronimus

Reputation: 9543

Firstly, it's very bad to have multiple instances of Random especially if they are created within milliseconds of each other (because they are seeded with random state of your computer, which doesn't change much over those time scales)

To make threads wait for each other, use a CyclicBarrier. The javadoc as an excellent example. However, I don't think that's what you're after as this will interfere with the race itself.

What you may want is a referee thread of some sorts that periodically prints the laps that the other threads have ran so far.

Upvotes: 2

Shubham Chaurasia
Shubham Chaurasia

Reputation: 2622

You can use https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CyclicBarrier.html for this.

Code goes like this

import java.util.Random;
import java.util.concurrent.CyclicBarrier;

public class ExThread implements Runnable {

String name;
Random r = new Random();
int count;
int sleepTimer;
CyclicBarrier barrier;

public ExThread(String name, CyclicBarrier barrier) {
    this.name = name;
    this.barrier = barrier;
}

public static void main(String[] args) throws InterruptedException {
    CyclicBarrier barrier = new CyclicBarrier(4);

    Thread t1 = new Thread(new ExThread("STAR", barrier));
    Thread t2 = new Thread(new ExThread("ELEFANT", barrier));
    Thread t3 = new Thread(new ExThread("PIGGY", barrier));
    Thread t4 = new Thread(new ExThread("DUCK", barrier));
    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

@Override
public void run() {
    try {
        for (int i = 0; i < 10; i++) {
            count++;
            sleepTimer = r.nextInt(1000) + 1;
            Thread.sleep(sleepTimer);
            System.out.println(
                    name + " Starts after " + sleepTimer + " milliseconds break");
            System.out.println(
                    name + " is on his " + count + " lap");
            barrier.await();
        }

        System.out.println(name + " completes the race!!!");
    } catch (Exception e) {
    }
}

}

Upvotes: 0

Related Questions