DEV Community

Cover image for Java Concurrency and Multithreading
Bellamer
Bellamer

Posted on

2

Java Concurrency and Multithreading

Concurrency in Java allows multiple threads to run simultaneously, enabling efficient use of CPU resources. Multithreading is a form of concurrency where multiple threads are executed within a single process.

Key Concepts

  1. Thread: A thread is the smallest unit of execution in a program. In Java, you can create a thread by extending the Thread class or implementing the Runnable interface.
  2. Synchronization: Synchronization is used to control the access of multiple threads to shared resources. It helps prevent thread interference and memory consistency errors.
  3. Executor Framework: The Executor framework provides a higher-level replacement for working with threads directly. It includes thread pools and task scheduling.
  4. Locks: Locks provide more extensive locking operations than synchronized methods and blocks. The java.util.concurrent.locks package contains several lock implementations.
  5. Atomic Variables: Atomic variables provide a way to perform atomic operations on single variables without using synchronization.

Code Example

Let's look at a simple example to understand how multithreading works in Java:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultithreadingExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 5; i++) {
            Runnable worker = new WorkerThread("" + i);
            executor.execute(worker);
        }
        executor.shutdown();
        while (!executor.isTerminated()) {
        }
        System.out.println("Finished all threads");
    }
}

class WorkerThread implements Runnable {
    private String command;

    public WorkerThread(String s) {
        this.command = s;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
        processCommand();
        System.out.println(Thread.currentThread().getName() + " End.");
    }

    private void processCommand() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return this.command;
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • ExecutorService: We create an ExecutorService with a fixed thread pool of 3 threads. This means that at most 3 threads will run concurrently.

  • WorkerThread: This class implements the Runnable interface. Each WorkerThread instance represents a task that will be executed by a thread.

  • Executing Tasks: We submit 5 tasks to the executor. The executor will manage the execution of these tasks using the available threads in the pool.

  • Shutdown: We call shutdown() on the executor to stop accepting new tasks and wait for the completion of submitted tasks.

  • Thread Execution: Each WorkerThread prints its start and end messages, and simulates work by sleeping for 5 seconds.

Under the Hood

  • Thread Creation: When a new thread is created, the JVM allocates a new stack for the thread and initializes it with the necessary data structures.

  • Context Switching: The JVM's thread scheduler manages the execution of threads. It uses context switching to switch between threads, saving and restoring the state of each thread.

  • Synchronization: When a thread enters a synchronized block, it acquires a lock on the object. Other threads trying to enter the same block are blocked until the lock is released.

  • Executor Framework: The Executor framework uses a thread pool to manage a pool of worker threads. This reduces the overhead of creating and destroying threads for each task.

Conclusion
Understanding Java concurrency and multithreading is essential for building high-performance applications. By leveraging the power of threads, you can create applications that efficiently utilize CPU resources and handle multiple tasks simultaneously.

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay