import java.util.HashMap ;
import java.util.Map ;
import java.util.concurrent.locks.Lock ;
import java.util.concurrent.locks.ReentrantLock ;
// Container holds a map of counters; since we want to
// update it concurrently from multiple threads, we
// add a Lock to synchronize access.
// Note that locks must not be copied, so if this
// class is passed around, it should be done by
// reference.
class Container {
private final Lock lock = new ReentrantLock ();
private Map < String , Integer > counters ;
public Container () {
this . counters = new HashMap <> ();
this . counters . put ( "a" , 0 );
this . counters . put ( "b" , 0 );
}
// Lock before accessing counters; unlock
// it at the end of the method.
public void inc ( String name ) {
lock . lock ();
try {
counters . put ( name , counters . get ( name ) + 1 );
} finally {
lock . unlock ();
}
}
public Map < String , Integer > getCounters () {
return new HashMap <> ( counters );
}
}
public class Mutexes {
public static void main ( String [] args ) throws InterruptedException {
Container c = new Container ();
// This function increments a named counter
// in a loop.
Runnable doIncrement = ( String name , int n ) -> {
for ( int i = 0 ; i < n ; i ++ ) {
c . inc ( name );
}
};
// Run several threads concurrently; note
// that they all access the same Container,
// and two of them access the same counter.
Thread t1 = new Thread (() -> doIncrement . run ( "a" , 10000 ));
Thread t2 = new Thread (() -> doIncrement . run ( "a" , 10000 ));
Thread t3 = new Thread (() -> doIncrement . run ( "b" , 10000 ));
t1 . start ();
t2 . start ();
t3 . start ();
// Wait for the threads to finish
t1 . join ();
t2 . join ();
t3 . join ();
System . out . println ( c . getCounters ());
}
}