Utilizzo dei semafori come lock per prevenire le race condition: si possono usare i semafori per bloccare (lock) l'accesso a una risorsa, ogni thread che vuole accedere all'utilizzo della risorsa deve prima chiamare la acquire() per prendere il lock. Quando il thread ha ultimato con la risorsa, deve chiamare release() per rilasciare il lock. Esempio di utilizzo di java.util.concurrent.Semaphore.
packagesharedobject;// java program to demonstrate // use of semaphores Locks importjava.util.concurrent.Semaphore;classWorkerThreadextendsThread{ Semaphore sem;SharedObject sharedObject;publicWorkerThread(Semaphore sem,SharedObject sharedObject,String threadName) { super(threadName); this.sem= sem;this.sharedObject= sharedObject; } @Overridepublicvoidrun() { // run by thread A if(this.getName().equals("A")) { System.out.println("Starting "+getName());try { // First, get a permit. System.out.println(getName()+" is waiting for a permit.");// acquiring the lock sem.acquire(); System.out.println(getName()+" gets a permit.");// Now, accessing the shared resource. // other waiting threads will wait, until this // thread release the lock for(int i=0; i <5; i++) { sharedObject.count++;System.out.println(getName()+": "+sharedObject.count);// Now, allowing a context switch -- if possible. // for thread B to execute Thread.sleep(10); } } catch (InterruptedException exc) { System.out.println(exc); } // Release the permit. System.out.println(getName()+" releases the permit.");sem.release(); } // run by thread B else { System.out.println("Starting "+getName());try { // First, get a permit. System.out.println(getName()+" is waiting for a permit.");// acquiring the lock sem.acquire(); System.out.println(getName()+" gets a permit.");// Now, accessing the shared resource. // other waiting threads will wait, until this // thread release the lock for(int i=0; i <5; i++) { sharedObject.count--;System.out.println(getName()+": "+sharedObject.count);// Now, allowing a context switch -- if possible. // for thread A to execute Thread.sleep(10); } } catch (InterruptedException exc) { System.out.println(exc); } // Release the permit. System.out.println(getName()+" releases the permit.");sem.release(); } } } // Driver class publicclassSemaphoreDemo{ publicstaticvoidmain(String args[]) throwsInterruptedException { // creating a Semaphore object // with number of permits 1 Semaphore sem =newSemaphore(1);SharedObject sharedObject =newSharedObject();// creating two threads with name A and B // Note that thread A will increment the count // and thread B will decrement the count WorkerThread mt1 =newWorkerThread(sem, sharedObject,"A");WorkerThread mt2 =newWorkerThread(sem, sharedObject,"B");// stating threads A and B mt1.start(); mt2.start(); // waiting for threads A and B mt1.join(); mt2.join(); // count will always remain 0 after // both threads will complete their execution System.out.println("count: "+sharedObject.count); } }
L'output dell'esecuzione, può essere:
Starting A
Starting B
A is waiting for a permit.
A gets a permit.
B is waiting for a permit.
A: 1
A: 2
A: 3
A: 4
A: 5
A releases the permit.
B gets a permit.
B: 4
B: 3
B: 2
B: 1
B: 0
B releases the permit.
count: 0
oppure:
Starting B
Starting A
B is waiting for a permit.
A is waiting for a permit.
B gets a permit.
B: -1
B: -2
B: -3
B: -4
B: -5
B releases the permit.
A gets a permit.
A: -4
A: -3
A: -2
A: -1
A: 0
A releases the permit.
count: 0