
Practice for this video
Please check what happens if you:
1. Call the start method two times
2. Call the join method before the start method
3. Set the daemon flag after starting a thread
4. Call the join method for a daemon thread
Also, please read the documentation for class Runnable and methods
start, join and setDaemon of the class Thread
Explore atomic variables that replace volatile counters with lock-free, thread-safe operations. Learn atomic types and methods like increment and get, get and increment, set, and compare and set, ABA problem.
Practice for this video
Find the throughput of your system, for that:
1. Add some mathematical work to the method process instead of the Thread.sleep call
2. Add a global counter which will count, how many items were processed (it can be an atomic variable)
3. Find the optimal number of producer and consumer threads
4. Find the best throughput of your system
Master Java concurrency concepts, including thread creation, join, interrupt, and daemon threads. Learn synchronization with the synchronized keyword, data races, volatile and atomic variables, wait/notify, producer-consumer patterns, and thread-local data.
Demonstrates data race: two threads increment a shared counter without synchronization, producing unpredictable results; introduce a shared lock and synchronized access to ensure correct values under heavy load.
Demonstrates race condition in a concurrent java environment and uses a volatile flag, a synchronized block, and a double-check to avoid loading already loaded data.
Starvation occurs when a thread cannot regularly access a shared resource due to long synchronized calls causing lock contention, with profiling from Java Mission Control identifying blocked threads.
Master multithreading by splitting work across threads and cores for higher throughput and responsiveness, using synchronized, volatile, and atomic constructs and wait/notify to avoid data races and livelock.
Explore how to use java.util.concurrent locks, including lock, unlock, tryLock, and lockInterruptible, with a re-entrant lock implementation and fairness considerations.
This lecture explains how a semaphore coordinates access to limited resources by tracking permits, such as processor cores, using acquire and release, with fairness and optional try or drain methods.
Practice for this video
Reimplement the merge-sort algorithm on your own using the CountDownLatch synchronization primitive
1. Create a queue for sorting tasks
2. Create a producer thread that publishes sorting tasks
3. Create consumer threads that take tasks from the queue and do sort
4. Create a method that waits for a competition of all sorting tasks and then does a merging stage
5. Add a test that checks that data are sorted correctly
Demonstrates copy-on-write collections, including copy-on-write array list and copy-on-write array set, showing safe reads with internal synchronization, and expensive updates with unsupported iterator remove.
Practice for this video
Implement your own capacity restricted queue:
1. With blocking methods put and take (it's not necessary to implement other methods)
2. Replace with it the LinkedBlockingQueue in our example
3. Write a test that checks that your queue works correctly with several producers and consumers
You can use the synchronized keyword and wait/notify calls or ReentrantLock and Condition variable
Explore the concurrent map interface and its java.util.concurrent implementations, including the concurrent hash map, to enable thread-safe, atomic updates for subscription contexts without external synchronization.
Practice for this video
You have to make refactoring of code from the video and create a MapReduce framework. For that
1. Create a MapReduce class
2. Parameters of the constructor should be:
text file (or path to the file)
map function
reduce function
3. Add a method execute
4. This method should return a collection of reduced Keys and Values
5. The type of Keys and Values should be generic. The Key can be Integer for example, and Value – Double.
6. Prepare a text file with several lines with numbers
7. Calculate the sum of values that are:
less than 100 (first key)
between 100-1000 (second key)
greater than 1000 (third key)
Explore the executor service in java.util.concurrent, learn to replace direct thread management with fixed, single, cached, and scheduled pools, and work with runnable and callable tasks and futures and shutdown.
Explore scheduling tasks after a delay or periodically with Java timer and the scheduled thread pool executor, covering timer task, daemon flag, cancellation, and future.
Explore the Java Stream API and parallel streams to process collections, map, filter, and collect, then compute max, min, and count with optional results.
Explore how throughput and latency shape performance in multi-threaded applications, using a producer-consumer example, atomic counters, and percentile-based latency measurements.
Explore testing in a java concurrency context, from unit tests for single methods to thread safety verification with barriers and latches, then stress and performance testing for real-world load.
In this course, we will discuss Java Concurrent and Multithreaded Programming in detail. The course covers basic topics such as threads creation, synchronization, memory model and a happens-before relationship. There are lectures about standard Java classes that help to write complex concurrent programs. Also, there are advanced sections about concurrent algorithms, performance and monitoring.