Play project with code examples to some toy problems to refresh my knowledge of Java Concurrency API.
NOTE: Some examples contain idioms not good for production code but are here just to remind me of oddities / gotchas / things to remember.
In a concurrent application if different threads generate
random number using Random
class e.g. by doing Random.nextInt(10)
then it can cause heavy contention on the seed and poor
performance.
Variations:
- Producer Consumer using
synchronized - wait
- Using
BlockedQueue
- Using
Lock
3 Variations:
-
Unbiased - Ensure that the reads and writes are in FIFO order and fair
-
Writer Biased - Once a writer requests, no reads are entertained.
-
Reader Biased - If a reader already has lock, another reader can continue to read even if a Writer is waiting.
- Semaphores and concept of lock ownership
- Semaphores like a CountdownLatch
- Controlling access to a pool of resources using Semaphores
- Demonstrate that countdown is just a count and not necessarily number of threads which counted down.
- CachedThreadPool (ThreadPoolExecutor)
- FixedSizeThreadPool (ThreadPoolExecutor)
- SingleThreadExecutor (Executor)
- ScheduledThreadpoolExecutors (ThreadPoolExecutor)
- Running Tasks periodically at a fixed rate
- Running Task Only once after an initial delay
- Running tasks periodically with a fixed delay between 2 instances
- Running tasks which don't return results
- Running tasks which return result
- Running multiple tasks and processing first result
- Running multiple tasks and processing all results
FutureTask
- How to execute another function post the task is complete.
- How to use CAS for better performance than locks
- Using CAS operations on an array of atomic variables for better performance
- LongAdder as maintaining total
- LongAdder as maintaining counter in stats
In case of maintaining total/counter, LongAdder results in better performance than AtomicLong under heavy contention.
Note: getting result is racy
In case of maintaining stats, this results in better performance than AtomicLong under heavy contention.
- Play ping pong between two threads using Exchanger
- Divide and Conquer using CyclicBarrier.
- Demonstrate that the barrier is automatically reset.
- Demonstrate that CyclicBarrier takes into account the number of threads and not the number of invocations
Separating concerns of submitting tasks and processing results
- Sample program to illustrate register(), arriveAndAwaitAdvance(), and arriveAndDeregister()
- Simulate a test where all students finish exercises together. Print messages whenever phase changes. Simulate a late student joining the exam.
1. - Understanding ForkJoinTask, RecursiveAction, RecursiveTask
- pool.invoke() vs. pool.execute() vs pool.submit()
2. Divide and Conquer using ForkJoinPool
- Using ForkJoinTask.invokeAll() [ Synchronous but better reuse of threads]
- Grouping results of sub-tasks
3. Asynchronous methods - ForkJoinTask.fork() and ForkJoinTask.join()
How to handle uncaught exceptions in the run() method of threads? ThreadGroups ThreadFactory
-
Show an example of deadlock.
-
Most textbook says to prevent deadlock, should take locks in the same order. Is it really true? Can you implement a situation where this leads to a "deadlock"
Hint: effect is same but it is called something else (not livelock :)