Download worksheet here (Amherst College login required)
A simple counter object (Counter.java)
public class Counter {
long count = 0;
public long getCount () { return count; }
public void increment () { count++; }
public void reset () { count = 0; }
}
What happens when multiple threads access it concurrently?
Compile and run the program with NUM_THREADS = 1. How many times is the counter incremented? How long does the program take to run?
Now set NUM_THREADS = 2. What happens when you run the program? Is the behavior what you’d expect?
Try a variety of of values for NUM_THREADS… 2, 4, 10, 100, 1000. Do you notice a pattern in the outputs?
Is this what you’d expect? Can you explain the behavior?
Random and ThreadLocalRandom
java.util.Random is thread-safe meaning that multiple threads can access it concurrently without causing issues with program correctness
java.util.concurrent.ThreadSafeRandom is not thread-safe, but makes a separate random generator for each thread
Compare the behavior of both!
With NUM_THREADS = 1, how long does your program take to execute?
Run the program with various values of NUM_THREADS as before. What pattern do you notice?
Modify RandomWorker.java so that it uses a thread local random number generator within the run method instead of the shared Random object. That is, replace the line
r.nextInt();
with
ThreadLocalRandom.current().nextInt();
The thread local random number generator creates a separate, independent number generator for each thread, rather than accessing the shared number generator passed to the constructor of the RandomWorker class.
Now run the program with various values of NUM_THREADS. What pattern do you see? Is it a similar pattern to before? How might you explain the difference (if any)?
If we’re not careful:
BadCounter)RandomTester)Sometimes we can achieve both speed and performance (RandomTester with ThreadLocalRandom)