/**
* 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) {
}
}
}
}