Java Threads Synchronizing Problem

Asked by At

I have the following 2 classes code that produce this result for instance:

Wainting for calculation to complete...
Calculator thread says HELLO!
T1 says that total is 10
Wainting for calculation to complete...
Wainting for calculation to complete...

Now threads are waiting but nobody is going to notify them. How can I force the threads from T1 to T3 to run before the "Calculator thread" wake em up?

public class Calculator implements Runnable{

  private int total;

  public int getTotal() {
    return total;
  }

  @Override
  public void run() {
    synchronized (this) {

        for (int i = 0; i < 5; i++) {
            total += i;
        }
        System.out.println(Thread.currentThread().getName() + " says HELLO!");
        notifyAll();
    }
  }
}


import static java.lang.System.out;

public class Reader implements Runnable{

  private Calculator c;


  public Reader(Calculator calc) {
    c = calc;
  }

  public Calculator getCalculator() {
    return c;
  }

  public static void main(String[] args) {

    Calculator calc = new Calculator();
    Reader read = new Reader(calc);

    Thread thread1 = new Thread(read);
    Thread thread2 = new Thread(read);
    Thread thread3 = new Thread(read);

    thread1.setName("T1");
    thread2.setName("T2");
    thread3.setName("T3");

    thread1.start();
    thread2.start();
    thread3.start();

    Thread calcThread = new Thread(read.getCalculator());
    calcThread.setName("Calculator thread");
    calcThread.start();
  }
}


  @Override
  public void run() {
      synchronized (c) {
          try {
              out.println("Wainting for calculation to complete...");
              c.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          out.println(Thread.currentThread().getName() + " says that " + "total is "  + c.getTotal());
      }

  }

}

3 Answers

0
arun_suresh On Best Solutions

Thread.join() may seem like an option in this particular situation. Since you have control of the main() function and you know exactly when each thread is starting.

A more general way to handle this situation is use a conditional variable and call the c.wait() within a loop to check the condition variable.

Basically add the isFinished field in the Calculator class :

public class Calculator implements Runnable {
...
  public volatile boolean isFinished = false
..
..

Then you replace c.wait() with :

...
while (!c.isFinished) {
  c.wait();
}
...

Finally in the `run() method of your Calculator class after calculating total, set the isFinished field

....
 for(int i = 0; ....
     total = += i;
 }
 c.isFinished = true
....
3
Peter Lawrey On

This is how I would write the code. Rather than trying to re-invent the wheel with wait/notify I would use concurrency library to do what is needed, a Future.

import java.util.concurrent.*;

public class Main {
    static final long start = System.nanoTime();

    static void log(String text) {
        double seconds = (System.nanoTime() - start) / 1e9;
        System.out.printf("%s %.6f - %s%n", Thread.currentThread().getName(), seconds, text);
    }

    static class Calculator implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            int total = 0;
            log("calculating total");
            for (int i = 0; i < 50000; i++)
                total += i;
            log("total is " + total);
            return total;
        }
    }

    static class Reader implements Callable<Void> {
        private final Future<Integer> totalFuture;

        public Reader(Future<Integer> totalFuture) {
            this.totalFuture = totalFuture;
        }

        @Override
        public Void call() throws ExecutionException, InterruptedException {
            log("Waiting for total.");
            int total = totalFuture.get();
            log("... got total= " + total);
            return null;
        }
    }

    public static void main(String... args) {
        ExecutorService es = Executors.newCachedThreadPool();
        Future<Integer> totalFuture = es.submit(new Calculator());
        es.submit(new Reader(totalFuture));
        es.submit(new Reader(totalFuture));
        es.submit(new Reader(totalFuture));
        es.shutdown();
    }
}

prints

pool-1-thread-1 0.008154 - calculating total
pool-1-thread-4 0.011356 - Waiting for total.
pool-1-thread-3 0.011292 - Waiting for total.
pool-1-thread-2 0.011128 - Waiting for total.
pool-1-thread-1 0.025097 - total is 1249975000
pool-1-thread-4 0.025351 - ... got total= 1249975000
pool-1-thread-3 0.025372 - ... got total= 1249975000
pool-1-thread-2 0.025380 - ... got total= 1249975000

After

thread3.start();

add the following to wait for the threads to finish.

thread1.join();
thread2.join();
thread3.join();
0
ngesh On

U may use Thread.join() method.. I'm not sure how abouts of good programming practices but that will work..