Вопрос: Как реализовать симуляцию JAVA используя многопоточность?

Лучший ответ:
По заявкам телезрителей :)import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class Simulation {

	private static final Random globalRandom = new Random(System.currentTimeMillis());
	
	public synchronized int getRandomIntInRangeEnclosed(int min, int max){
		return globalRandom.nextInt((max - min + 1) + min);
	}
	
	private final static int CUSTOMER_NUMBER = 3000;
	private final static int DESK_NUMBER = 6;

	public final int ITEM_DURATION_S_MIN = 3;
	public final int ITEM_DURATION_S_MAX = 8;

	public final CustomerFactory customerFactory = new CustomerFactory(this, CUSTOMER_NUMBER);

	public final ArrayList<DeskReport> results = new ArrayList<DeskReport>(DESK_NUMBER);
	
	public void perform(){
		ExecutorService executor = Executors.newFixedThreadPool(DESK_NUMBER);
		for (int i = 1; i <= DESK_NUMBER; i++) {
			executor.submit(new Desk(this, i));
		}

		executor.shutdown();
        try {
            executor.awaitTermination(20, TimeUnit.SECONDS);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
	}
	
	public void printResult(){
		int maxTimeS = 0;
		int maxItems = 0;
		int maxCustomers = 0;
		
		int minItems = Integer.MAX_VALUE;
		int minCustomers = Integer.MAX_VALUE;
		
		for(DeskReport r : results){
			if(r.getSpentTime() > maxTimeS){
				maxTimeS = r.getSpentTime();
			}
			
			if(r.getSoldItemCount() > maxItems){
				maxItems = r.getSoldItemCount();
			}
			if(r.getSoldItemCount() < minItems){
				minItems = r.getSoldItemCount();
			}
			
			
			if(r.getServedCustomerCount() > maxCustomers){
				maxCustomers = r.getServedCustomerCount();
			}
			if(r.getServedCustomerCount() < minCustomers){
				minCustomers = r.getServedCustomerCount();
			}
			
		}
		
		Date date = new Date(maxTimeS * 1000L);
		DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
		String dateFormatted = formatter.format(date);
		
		
		System.out.println("---------------- RESULTS ----------------");
		System.out.println(DESK_NUMBER + " desks served " + CUSTOMER_NUMBER + " customers in " + dateFormatted);
		System.out.println("Troughput min ~ max:");
		System.out.println(minItems + "\t~\t" + maxItems + " \titems/desk");
		System.out.println(minCustomers + "\t~\t" + maxCustomers + "\tcustomers/desk");
	}
	
	public static void main(String[] args) {
		Simulation sim = new Simulation();
		sim.perform();
		sim.printResult();
	}
}
public class CustomerFactory {

	private Simulation simulation;
	private int capacity = 0;
	
	public CustomerFactory(Simulation simulation, int capacity){
		this.simulation = simulation;
		this.capacity = capacity;
	}

	public synchronized Customer getInstanceWithRandomCapacity(){
		if(capacity-- > 1){
			return new Customer(this.simulation.getRandomIntInRangeEnclosed(1,20));
		} else {
			return null;
		}
	}
	
}

public class Desk implements Runnable{
	private Simulation s = null;
	private int deskNo = 0;

	private int servedCustomerCount = 0;
	private int soldItemCount = 0;
	private int spentTime = 0;
	
	public Desk(Simulation s, int deskNo) {
		this.s = s;
		this.deskNo = deskNo;
	}
	
	public void run() {
		System.out.println("Desk " + deskNo + " opening...");

		Customer c = null;
		while ((c = s.customerFactory.getInstanceWithRandomCapacity()) != null) {
			servedCustomerCount++;
			for(int i=c.getItemCount(); i>1; i--){
				soldItemCount++;
				spentTime += s.getRandomIntInRangeEnclosed(s.ITEM_DURATION_S_MIN, s.ITEM_DURATION_S_MAX);
			}
			//get short break after each customer ;)
			sleep(Long.valueOf(s.getRandomIntInRangeEnclosed(s.ITEM_DURATION_S_MIN, s.ITEM_DURATION_S_MAX)));
		}
		
		s.results.add(new DeskReport(deskNo, servedCustomerCount, soldItemCount, spentTime));
		System.out.println("Desk " + deskNo + "\tclosing.\tcustomers " + servedCustomerCount + "\titems " + soldItemCount + "\ttime(s) " + spentTime);
	}
	
	private void sleep(long ms){
		try {
			Thread.sleep(ms);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class DeskReport {
	private int deskNo = 0;
	private int servedCustomerCount = 0;
	private int soldItemCount = 0;
	private int spentTime = 0;
	
	public DeskReport(int deskNo, int servedCustomerCount, int soldItemCount, int spentTime){
		this.deskNo = deskNo;
		this.servedCustomerCount = servedCustomerCount;
		this.soldItemCount = soldItemCount;
		this.spentTime = spentTime;
	}
	
	public int getDeskNo() {
		return deskNo;
	}

	public int getServedCustomerCount() {
		return servedCustomerCount;
	}

	public int getSoldItemCount() {
		return soldItemCount;
	}

	public int getSpentTime() {
		return spentTime;
	}
	
}

public class Customer{
	private int itemCount = 0;
	
	public Customer(int itemCount){
		this.itemCount = itemCount;
	}
	
	public int getItemCount(){
		return this.itemCount;
	}
}
Симуляция примитивнейшая, демонстрирует скорее работу планировщика потоков, нежели магазина. Но если ее развить: смоделировать неравномерное "поступление" покупателей в магазин, очередь к кассам, случайный выбор кассы покупателем и т.д., можно узнать много интересного о работе магазинов. А пока, чтоб не было совсем уж бессмысленно, считается хоть какая-то примитивная статистика.

Худший ответ:
Я бы сделал так:
1. коллекция касс
2. коллекция покупателей и у каждого коллекция товаров
3. время обработки одного товара = 3000мс
4. время между сменой покупателя = 5000мс
Запуск очереди покупателей по кассам.
Пока все кассы заняты - остальные покупатели ждут
При освобождении кассы новый покупатель идет в нее
Время пока покупатель занимает кассу = количество товаров * на время обработки одного товара и плюс время смены покупателя