package com.example.sync;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class ConcurrentCollectionExample {
	private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
	
	public void add(String key, Integer value) {
		map.put(key, value);
		System.out.println(Thread.currentThread().getName() 
				+ " added (" + key + ", " + value + ")");
	}
	
	public Integer get(String key) {
		return map.get(key);
	}
	
	public void printMap() {
		// stream processing with lambda expression
		map.forEach((key, value) -> System.out.println(key + ": " + value));
		
//		for (Map.Entry<String, Integer> entry : map.entrySet()) {
//			System.out.println(entry.getKey() + ": " + entry.getValue());
//		}
	}
}

class WorkerCC implements Runnable {
	private ConcurrentCollectionExample example;
	private String key;
	private Integer value;
	
	public WorkerCC(ConcurrentCollectionExample example, String key, Integer value) {
		this.example = example;
		this.key = key;
		this.value = value;
	}
	
	public void run() {
		example.add(key, value);
	}
}

public class ConcurrentCollectionDemo {

	public static void main(String[] args) {
		ConcurrentCollectionExample example = new ConcurrentCollectionExample();
		ExecutorService executor = Executors.newFixedThreadPool(3);
		
		executor.execute(new WorkerCC(example, "One", 1));
		executor.execute(new WorkerCC(example, "Two", 2));
		executor.execute(new WorkerCC(example, "Three", 3));
		executor.execute(new WorkerCC(example, "Four", 4));
		executor.execute(new WorkerCC(example, "Five", 5));
		
		executor.shutdown();
		while(!executor.isTerminated()) {
			// just to wait until all threads die
		}
		
		System.out.println("Final contents of the map: ");
		example.printMap();
	}

}
