import java.util.Arrays;
import java.util.concurrent.Semaphore;

/**
 * {@link <a href=
 * "https://[Log in to view URL]"
 * target= "_blank">Semaforo : sincronizzazione in accesso, dis-accopiato dalla sincronizzazione alla risorsa</a>}
 * 
 * @author itammb ( Italia Massimiliano Buscati )
 * @version JDK 1.15
 *
 */
class Main {
	private static class ATMQueue {
		private Semaphore semaphore; // monitor sugli accessi
		private boolean[] freeATMs;  // ATM liberi 

        /**
		 * @see Semaphore#acquire()
		 * @see Semaphore#release()
		 * 
		 */
		public void withDrawMoney() {
			try {
				semaphore.acquire();

				// ATM disponibile
				int atmMachine = getAvailable();

				// concede esecuzione ad altri thread
				Thread.sleep((long) (Math.random() * 1000));

				System.out.println(Thread.currentThread().getName()
						+ " :: correntista -> ha eseguito prelievo moneta sul ATM " + atmMachine);

				releaseATM(atmMachine);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				semaphore.release();
			}
		}

		public boolean showtdown() {
			synchronized (freeATMs) {
				for (int i = 0; i < freeATMs.length; i++)
					if (!freeATMs[i])
						return false;
			}

			return true;
		}

		private int getAvailable() {
			int freeAtm = -1; // tutti gli ATM sono occupati
			boolean notExit = true;

			synchronized (freeATMs) {
				for (int i = 0; i < freeATMs.length && notExit; i++)
					if (freeATMs[i]) {
						freeATMs[i] = notExit = false;
						freeAtm = i; // primo ATM trovato libero
					}

				System.out.println("ATM numero : " + freeAtm + " è disponibile");

				return freeAtm;
			}
		}

		private void releaseATM(int numberATM) {
			synchronized (freeATMs) {
				freeATMs[numberATM] = true;

				System.out.println("ATM numero : " + numberATM + " è di nuovo disponibile");
			}
		}

		public ATMQueue(int numberATM) {
			semaphore = new Semaphore(numberATM);

			// tutti i bancomat sono liberi
			freeATMs = new boolean[numberATM];
			Arrays.fill(freeATMs, true);
		}
	}

	private static class WithdrawMoneyTask implements Runnable {
		private final ATMQueue atmQueue;

		@Override
		public void run() {
			System.out.println(Thread.currentThread().getName() + " :: correntista -> in attesa");

			// prelieno
			atmQueue.withDrawMoney();
		}

		public WithdrawMoneyTask(ATMQueue atmQueue) {
			this.atmQueue = atmQueue;
		}
	} // WithdrawMoneyTask

	private static class UniTest {

		public void simulate(int numberATM, int accountHolder) {			
			ATMQueue atmQueue = new ATMQueue(numberATM); // ATM

			// correntisti : thread pool  
			Thread thread[] = new Thread[accountHolder];
			for (int i = 0; i < accountHolder; i++)
				thread[i] = new Thread(new WithdrawMoneyTask(atmQueue), "Thread " + i);
			
			for (int i = 0; i < accountHolder; i++) 
				thread[i].start();

			// quando tutti i correntisti hanno svolto le operazioni di cassa automatica, il processo termina
			while (atmQueue.showtdown())
				;
		}
	}

	public static void main(String args[]) {
		// Unit test - simulazione semaforo
		new UniTest().simulate(3, 10);
	}

}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: