import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class TestConcurrency {
    public static void main (String[] args) throws InterruptedException, ExecutionException {

        //Use Runnable to process orders and then shipments
        String[] orders = {"Hat", "Shirt", "Trousers", "Shoes"};
        String[] shipments = {"Shipment 1", "Shipment 2", "Shipment 3"};
        Runnable processOrdersR = () -> {
            for (String order : orders) {
                System.out.println("Processed order for " + order);
            }
        };
        Runnable processShipmentsR = () -> {
            for (String shipment : shipments) {
                System.out.println("Processed shipment for " + shipment);
            }
        };
        Thread thread = new Thread(processOrdersR);
        thread.start();
        // Wait until orders thread is complete before starting shipments thread
        thread.join();
        Thread thread2 = new Thread(processShipmentsR);
        thread2.start();
        // Wait until shipments thread is complete before resuming main method
        thread2.join();

        // Use ExecutorService and Callable to run order and shipment threads
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Callable<String> processOrdersC = () -> {
            int i = 0;
            for (String order : orders) {
                i++;
            }
            return "Processed " + i + (i!=1 ? " orders" : " order");
        };
        Callable<String> processShipmentsC = () -> {
            int i = 0;
            for (String shipment : shipments) {
                i++;
            }
            return "Processed " + i + (i!=1 ? " shipments" : " shipment");
        };
        List<Callable<String>> threadsToRun = new ArrayList<>();
        threadsToRun.add(processOrdersC);
        threadsToRun.add(processShipmentsC);
        List<Future<String>> results = executorService.invokeAll(threadsToRun);

        executorService.shutdown();
        if (executorService.awaitTermination(5, TimeUnit.SECONDS)) {
            System.out.println("Future results...");
            for (Future<String> result : results ) {
                System.out.println(result.get());
            }
            System.out.println("All threads processed");
        }
        else {
            // threads did not complete in the expected time, so force shutdown of ExecutorService
            System.out.println("Threads did not complete in a timely manner, forcing shutdown...");
            executorService.shutdownNow();
        }
    }
}