/** * Java solutions to H2O synchronization problem * * Main thread will generate H or O atoms which you need to synchronize to make water * * Reminder: Java parameter passing are by value * * We create a shared resources class to allow each thread access them * **/ import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.Random; //A shared resource/class class Shared { private Lock lock; private AtomicInteger cH; private AtomicInteger cO; private Semaphore SemH; private Semaphore SemO; public Shared() { lock = new ReentrantLock(); cH = new AtomicInteger(); // Inits variable to zero cO = new AtomicInteger(); SemH = new Semaphore( 0 ); // Semaphore variable initialized to 0 SemO = new Semaphore( 0 ); } public void getLock() { lock.lock(); } public void releaseLock() { lock.unlock(); } public int getH() { return cH.get(); } public int getO() { return cO.get(); } public void IncH() { cH.getAndIncrement(); } public void DecH() { cH.getAndDecrement(); } public void IncO() { cO.getAndIncrement(); } public void DecO() { cO.getAndDecrement(); } public void SignalH() { this.SemH.release(); } public void SignalO() { this.SemO.release(); } public void WaitH() { try { this.SemH.acquire(); } catch ( InterruptedException e ) { } } public void WaitO() { try { this.SemO.acquire(); } catch ( InterruptedException e ) { } } } class Particle extends Thread { Random r; int number; Shared resources; // Create all shared variables, only one instance public Particle( int i, Shared res ) { this.number = i; this.r = new Random(); this.resources = res; } @Override public void run() { if ( 0 == (r.nextInt() & 3) ) { // Create a new particle, randomly select hydrogen and oxygen this.O( this.number ); } else { this.H( this.number); } } /** * Oxygen atom method * * Check for two hydrogen atoms to make water, else wait * **/ public void O( int id ) { resources.getLock(); // Get exclusive acess System.out.println("Starting O thread " + this.number + " ... cO(" + resources.getO() + "), cH(" + resources.getH() + ")" ); if ( resources.getH() > 1 ) { System.out.println("\t O particle thread " + id + " is making water :) ... cO(" + resources.getO() + "), cH(" + resources.getH() + ")" ); resources.DecH(); resources.DecH(); // Report use of two hydrogen atoms resources.releaseLock(); // Release lock resources.SignalH(); // Signal to required hydrogen atoms resources.SignalH(); } else { resources.IncO(); // Report one more oxygen atom resources.releaseLock(); // Release lock and wait resources.WaitO(); } } /** * * Hydrogen atom method * * Check for another hydrogen and one oxygen to make water, else wait **/ public void H( int id ) { resources.getLock(); System.out.println("Starting H thread " + this.number + " ... cO(" + resources.getO() + "), cH(" + resources.getH() + ")" ); if ( (resources.getH() > 0) && (resources.getO() > 0) ) { System.out.println("\t H particle thread " + id + " is making water :) ... cO(" + resources.getO() + "), cH(" + resources.getH() + ")" ); resources.DecH(); resources.DecO(); resources.releaseLock(); resources.SignalH(); resources.SignalO(); } else { resources.IncH(); resources.releaseLock(); resources.WaitH(); } } } // Driver class public class Agua { public static void main(String args[]) throws InterruptedException { Shared agua = new Shared(); Thread particles[] = new Thread[ 100 ]; for ( int i = 0; i < 100; i++ ) { particles[ i ] = new Particle( i, agua ); particles[ i ].start(); } // waiting for threads for ( int i = 0; i < 100; i++ ) { try { particles[ i ].join(); } catch ( InterruptedException e) { } } } }