Multithreading

Thread Synchronization

  • synchronized keyword is used to achieve thread synchronization. It can be used with a method or a block of code.

  • wait() and notify() methods are used to coordinate between threads. wait() method causes a thread to wait until another thread signals (by calling notify() method).

  • join() method is used to wait for a thread to finish its execution before moving on to the next task.

  • volatile keyword is used to make sure that the changes made to a variable by one thread are immediately visible to other threads.

Thread Pooling

  • A thread pool is a group of pre-initialized threads that are ready to execute tasks.

  • ExecutorService is an interface that represents an executor that can execute tasks asynchronously.

  • ThreadPoolExecutor is a class that provides a thread pool implementation.

  • submit() method is used to submit a task to the thread pool.

  • shutdown() method is used to shutdown the thread pool after completing all the tasks.

Concurrent Collections

  • Java provides thread-safe implementations of common collections in the java.util.concurrent package.

  • Examples: ConcurrentHashMap, ConcurrentLinkedQueue, CopyOnWriteArrayList, etc.

  • These collections are designed to be used in multi-threaded environments without the need for external synchronization.

Locks

  • Java provides a Lock interface which can be used to achieve thread synchronization.

  • ReentrantLock is a class that implements the Lock interface.

  • tryLock() method is used to try to acquire the lock without waiting. It returns immediately with a boolean value indicating whether the lock was acquired or not.

  • lockInterruptibly() method is used to acquire the lock while waiting for the lock to be released. If the thread is interrupted while waiting, an InterruptedException is thrown.

Atomic Variables

  • Atomic variables are thread-safe variables that can be updated atomically.

  • Java provides a set of classes in the java.util.concurrent.atomic package that implement atomic variables, such as AtomicInteger, AtomicLong, AtomicBoolean, etc.

  • Atomic variables are designed to be used in multi-threaded environments without the need for external synchronization.

Thread Safety

  • A class is thread-safe if it can be used by multiple threads at the same time without causing any issues.

  • Immutable objects are inherently thread-safe because they cannot be modified after they are created.

  • Synchronization is required to achieve thread safety for mutable objects.

  • Locking can cause contention and degrade performance, so it should be used judiciously.

  • Thread-safety can also be achieved using atomic variables and concurrent collections.

Executors

  • Executors provide a simple way to create and manage threads.

  • Executors provide a number of methods to create different types of thread pools, such as fixed thread pool, cached thread pool, and scheduled thread pool.

  • Executors provide methods to execute tasks asynchronously and return the result in the form of a Future object.

  • Executors can also be used to schedule tasks for execution at a later time.

Fork/Join Framework

  • The fork/join framework is a concurrency mechanism introduced in Java 7.

  • The framework is designed for recursive algorithms that can be broken down into smaller subtasks.

  • The framework provides a ForkJoinPool class that manages a pool of worker threads and a RecursiveTask class that represents a task that can be broken down into smaller subtasks.

  • The invoke() method of the ForkJoinPool class is used to submit a RecursiveTask to the pool for execution.

Thread Local Variables

  • Thread local variables are variables that are local to a thread.

  • Each thread has its own copy of the thread local variable.

  • Thread local variables can be used to store thread-specific information, such as user preferences or database connections.

  • Java provides a ThreadLocal class to create thread local variables.

Thread Deadlock

  • Thread deadlock occurs when two or more threads are blocked, waiting for each other to release a resource.

  • Deadlocks can occur when multiple threads acquire locks in a different order.

  • To avoid deadlock, it is important to always acquire locks in the same order.

  • Deadlocks can also occur when multiple threads wait indefinitely for a resource that is held by another thread.

Thread Starvation

  • Thread starvation occurs when a thread is unable to acquire the resources it needs to continue executing.

  • Starvation can occur when a thread is blocked waiting for a lock that is held by another thread.

  • To avoid starvation, it is important to ensure that all threads have a fair chance of acquiring the resources they need.

  • Java provides a FairLock class that ensures fairness in locking.

Last updated