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
)