1

I wanted to do make a program that allows to start x threads and all threads are supposed to do a job:

counting average from Math.random() when number > 0.

I started doing it without volatile boolean and it did not work. But with volatile boolean it works as expected.

Could anyone explain me please why? Would it be possible to make it differently?

public class Worker extends Thread {

    private int number;
    private double average = 0;
    private volatile boolean cancelled;

    public Worker(int number) {
        this.number = number;
        cancelled = false;
    }

    public void run() {
            while (!cancelled) {
                if (number > 0) {
                    for (int i = 0; i < number; i++) {
                        average += Math.random();
                        if (number - 1 == i) {
                            average = average/this.number;
                            number = 0;
                            System.out.println(Thread.currentThread().getName() + " average is: " + average);
                        }
                    }
                }
        }
        System.out.println(Thread.currentThread().getName() + " is cancelled...");
    }


    public void cancel() {
        this.cancelled = true;
    }

    public double getAverage() {
        return this.average;
    }

    public void setNumber(int number) {
        this.number = number;
    }

}

    public class Executor {

    private List<Worker> activeThreads;
    private Double[] array;

    public Executor(){
        activeThreads = new ArrayList<>();
    }

    public void createThreads(int number, int count){
        for(int i = 0; i < number; i++){
            Worker worker = new Worker(count);
            worker.setName("Thread " + i);
            activeThreads.add(worker);
            array = new Double[number];
            worker.start();
        }
    }

    public void cancelThreads(){
        int count = 0;
        for(Worker w : activeThreads){
            w.cancel();
            try {
                  array[count] = w.getAverage();
                  count++;
                  w.join();
            } catch (InterruptedException ex) {
                System.out.println("Interrupted exception");
                Thread.currentThread().interrupt();
            }
        }
        getFinalAverage();
    }

    public void startJob(int num){
        activeThreads.forEach(t -> t.setNumber(num));
    }


    public void getActiveThreads(){
        System.out.println(Thread.getAllStackTraces().keySet().size());
    }

    private void getFinalAverage(){
        double finalAverage = 0;
        for(Double d : Arrays.asList(array)){
            finalAverage += d;
        }
        finalAverage = finalAverage / array.length;
        System.out.println("Final average is " + finalAverage);
    }
}
Rishabh Agarwal
  • 1,988
  • 1
  • 16
  • 33
Arth
  • 331
  • 3
  • 14
  • If you want to share mutable state between threads in Java, you need some sort of thread synchronization, `volatile` fields being one of the options. Without that, there are no guarantees that threads can read data written by other threads timely or at all. – Thilo Oct 21 '18 at 12:26
  • Thanks for your response. I cannot still understand my example - I am making x threads and always new instance, so i thought that boolean without volantile will be sufficient, but I do not understand why It is not... :( – Arth Oct 21 '18 at 12:37
  • You want the main thread to set the `cancelled` field to `true` and have that change be visible to the worker thread. Without `volatile` (or some other mechanism) that is not guaranteed to happen. The worker thread might just forever see the initial value of `false`. – Thilo Oct 21 '18 at 12:55
  • Java can "optimize" your program (i.e., re-write it for efficiency.) To get the best efficiency, it is allowed to assume that variables are not shared by threads except in special cases. `volatile` is one such case: Java must assume that a `volatile` variable could be changed by any thread at any time. If you have non-volatile `boolean b;` and you have a loop, `while(b){...}`. The compiler can change that to `while(true)` if it can prove that the loop never sets `b=false`. But, if `b` is `volatile`, the system must assume that some other thread could set `b=false`. – Solomon Slow Oct 22 '18 at 01:14

0 Answers0