Search code examples
javamultithreadingcallablethread-synchronizationreentrantlock

Why else condition not shows over console for waiting Thread. if i'm using future.get() method?


Here in office instance getsum() returns sum of n number digits and only one Thread allowed to complete the calculation at a time with a sleep of 1 seconds. During this time other Thread will try for lock, If Thread not get lock it prints else condition over console and iterate in do-while loop until get completed

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Office {
    private ReentrantLock lock = new ReentrantLock(true);

    public void login(String name) {
        System.out.println("Good Morning : " + name);
    }

    public long getSum(String name, long number) {
        long sum = 0;
        try {
            do {
                if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
                    for (int i = 1; i <= number; i++) {
                        sum = sum + i;
                        Thread.sleep(1000);
                    }
                    lock.unlock();
                    break;
                } else {
                    System.out
                            .println("waiting for lock : " + name + " " + Thread.currentThread() + " " + "is waiting");
                }
            } while (true);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return sum;
    }

    public void logout(String name) {
        System.out.println("Good night : " + name);
    }
}
import java.util.concurrent.Callable;

public class MyCallable implements Callable {
    private Office office;
    private String name;
    private long number;

    public MyCallable(Office office, String name, long number) {
        this.office = office;
        this.name = name;
        this.number = number;
    }

    @Override
    public Object call() throws Exception {
        office.login(name);
        long total = office.getSum(name, number);
        office.logout(name);
        return total + " " + name;
    }
}

Here future.get() if we are using we can't get Thread waiting statement over console, and if we are not the Waiting statement successfully displays over console. I'm bit curious why it's happening as get() shows result only when Thread gets completed and Waits if necessary for the computation to complete, and then retrieves its result. How it can affect the else statement in getSum of office instance

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) {
        long total = 0;
        String name = null;
        Office office = new Office();
        MyCallable myCallable[] = { new MyCallable(office, "Nik", 10), new MyCallable(office, "Dev", 20),
                new MyCallable(office, "push", 30), new MyCallable(office, "Sam", 40) };

        ExecutorService service = Executors.newFixedThreadPool(2);
        for (MyCallable callable : myCallable) {

            Future future = service.submit(callable);
            try {
                String result[] = future.get().toString().split(" ");
                total = Integer.parseInt((result[0]));
                name = result[1];
                System.out.println(name + " " + total);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }

        }
        service.shutdown();
    }
}

I'm getting output without any waiting Thread else statement with use of future.get() method

OUTPUT:
Good Morning : Nik
Good night : Nik
Nik 55
Good Morning : Dev
Good night : Dev
Dev 210
Good Morning : push
Good night : push
push 465
Good Morning : Sam
Good night : Sam
Sam 820

Here I'm expecting else statement also for waiting Threads but not getting that if I use future.get();


Solution

  • You need to submit all futures first, and only then try calling .get(). Here is your main method modified:

        public static void main(String[] args) {
            long total = 0;
            String name = null;
            Office office = new Office();
            MyCallable myCallable[] = { 
                    new MyCallable(office, "Nik", 10), 
                    new MyCallable(office, "Dev", 20),
                    new MyCallable(office, "push", 30), 
                    new MyCallable(office, "Sam", 40) };
    
            ExecutorService service = Executors. newFixedThreadPool(2);
            List<Future> futures = new ArrayList<>();
            for (MyCallable callable : myCallable) {
                futures.add(service.submit(callable));
            }
            for (Future future : futures) {
                try {
                    String result[] = future.get().toString().split(" ");
                    total = Integer.parseInt((result[0]));
                    name = result[1];
                    System.out.println(name + " " + total);
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            service.shutdown();
        }
    

    This produces the following output:

    Good Morning : Dev
    Good Morning : push
    waiting for lock : Dev Thread[pool-1-thread-2,5,main] is waiting
    waiting for lock : Dev Thread[pool-1-thread-2,5,main] is waiting