import java.util.concurrent.*;
import java.util.Scanner;

public class OutOfSync {

	public static final int WORKERS = 10;
	
	
	public static void main(String[] args) {
		DataCollector shared = new DataCollector();
		
		ExecutorService threadExecutor = Executors.newCachedThreadPool();
		
		SumWorker[] workers = new SumWorker[WORKERS];
		for(int i = 0; i < WORKERS; i++){
			//create, store and start workers
			workers[i] = new SumWorker(shared);
			threadExecutor.execute(workers[i]);
		}
		System.out.println("Done creating.");
		
		//wait for the user to type something
		Scanner in = new Scanner(System.in);
		System.out.println("Type anything to end: ");
		in.nextLine();
		
		//tell the workers to finish
		for(SumWorker w: workers){
			w.finish();
		}
		
		//returns immediately, but takes no new workers
		threadExecutor.shutdown();
		
		//wait for all the threads to complete
		try {
			threadExecutor.awaitTermination(5, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//output results
		//sum up workers' totals
		int sums = 0;
		for(SumWorker w: workers){
			sums += w.getMyTotal();
		}
		
		System.out.printf("Sum: %d =?= collector: %d =?= shared: %d\n",
				sums, shared.getTotal(), SumWorker.sharedSum);
		
	}

}

//worker  class
class SumWorker implements Runnable{

	public static long sharedSum = 0;
	
	
	private DataCollector data;
	private long myTotal;

	//don't use a cached copy of this variable
	private boolean done;

	public SumWorker(DataCollector dc){
		data = dc;
		myTotal = 0;
		done = false;
	}

	@Override
	public void run(){
		while(!done){
			myTotal++;
			data.increment();
			sharedSum++;
		}
	}

	public void finish(){
		done = true;
	}

	public long getMyTotal(){
		return myTotal;
	}
	
}


//a class to hold the shared data
class DataCollector {
	private long total;
	
	public DataCollector(){
		total = 0;
	}
	
	public void increment(){
		total++;
	}
	
	public void decrement(){
		total--;
	}
	
	public long getTotal(){
		return total;
	}
}