Udemy
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
Turn what you know into an opportunity and reach millions around the world.
Learn More
Your cart is empty.
Keep shopping
Java Concurrency & Multithreading in Practice
Rating: 5.0 out of 5(9 ratings)
116 students

Java Concurrency & Multithreading in Practice

Master threads, synchronization, and concurrent utilities to write fast, safe, and scalable Java programs
Last updated 4/2026
English

What you'll learn

  • Create and manage Java threads using both Runnable and Thread with full lifecycle control
  • Identify and fix race conditions in shared mutable state with synchronized blocks and methods
  • Use volatile, AtomicInteger, and other atomic classes for lock-free thread safety in Java
  • Apply ReentrantLock and ReadWriteLock for flexible, high-performance explicit locking
  • Detect, reproduce, and prevent deadlocks using consistent lock ordering strategies
  • Build scalable task execution pipelines with ExecutorService and thread pools
  • Retrieve asynchronous results using Callable and Future in Java concurrent programs
  • Coordinate complex multi-thread workflows with CountDownLatch and CyclicBarrier
  • Compose non-blocking asynchronous pipelines with CompletableFuture
  • Use ConcurrentHashMap and thread-safe collections for safe concurrent data access

Course content

12 sections103 lectures10h 30m total length
  • Creating Threads: Runnable vs Thread12:42

    Every concurrent Java program begins with a thread, and Java gives you two classic ways to spin one up: extending the Thread class or implementing the Runnable interface. In this lecture, you will write both approaches side by side in Java, run them, and observe how each thread prints output independently of the main thread. You will discover why Runnable is generally preferred over extending Thread — it keeps your class hierarchy flexible and separates the task from the execution mechanism. By comparing the console output from both approaches, you will see firsthand that threads run concurrently and their print order is not guaranteed, which is your first taste of non-determinism in multithreaded Java programs.



  • Thread Lifecycle and States12:24

    A Java thread is not just "running" or "done" — it moves through a series of well-defined states including NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED. In this lecture, you will write a short Java program that creates a thread, queries its state at various points using Thread.getState(), and prints those states to the console. You will simulate transitions by calling methods like sleep() and join() and observe how the thread's reported state changes accordingly. Understanding this lifecycle is essential because many concurrency bugs stem from assumptions about what state a thread is in, and once you can read a thread's state, debugging multithreaded Java code becomes far less mysterious.



  • Sleeping, Yielding, and Joining Threads12:26

    Three of the most commonly used thread-control methods in Java are sleep(), yield(), and join(), and each one influences thread scheduling in a different way. In this lecture, you will write a Java program that launches multiple threads and uses Thread.sleep() to pause execution for a specified duration, Thread.yield() to hint that the current thread is willing to give up the CPU, and Thread.join() to make one thread wait until another finishes. By printing timestamps and thread names to the console, you will observe how sleep introduces predictable delays, yield has a subtle and platform-dependent effect, and join creates a clear ordering between threads that would otherwise run independently.



  • Daemon Threads vs User Threads12:33

    Not all Java threads are created equal — some are meant to live only as long as the application needs them, and those are called daemon threads. In this lecture, you will write a Java program that creates both a daemon thread and a user thread, sets the daemon flag before starting, and observes what happens when the main thread finishes. You will see that the JVM does not wait for daemon threads to complete before shutting down, which makes them ideal for background housekeeping tasks like monitoring or cleanup. The console output will clearly demonstrate the abrupt termination of the daemon thread, reinforcing why you should never use daemon threads in Java for work that absolutely must finish.



  • Handling Thread Interruptions13:54

    In Java, you cannot forcefully kill a thread — instead, you politely ask it to stop by calling interrupt(), and the thread decides how to respond. In this lecture, you will write a Java program where one thread interrupts another that is either sleeping or running a loop, and you will handle the InterruptedException as well as check the interrupted flag using Thread.interrupted() and isInterrupted(). The console output will show you exactly when the interruption is detected and how the target thread responds. Mastering interruption handling in Java is critical because it is the cooperative cancellation mechanism that the entire concurrency framework relies on, and mishandling it leads to threads that refuse to stop or silently swallow important signals.

  • Thread Priority and Scheduling12:14

    Java allows you to assign priority levels to threads using setPriority(), ranging from MIN_PRIORITY (1) to MAX_PRIORITY (10), hinting to the thread scheduler which threads should get more CPU time. In this lecture, you will write a Java program that creates several threads with different priorities, has each one perform a counting task, and prints the results to see whether higher-priority threads completed more work. You will learn that thread priority in Java is merely a suggestion to the operating system's scheduler and that results vary across platforms, which is why you should never rely on priority alone for correctness. This lecture gives you a realistic understanding of Java's scheduling model and why designing your concurrency logic to be priority-independent is a best practice.



Requirements

  • Solid understanding of Java fundamentals including classes, interfaces, and inheritance
  • Familiarity with Java collections such as List, Map, and basic data structures
  • Ability to write, compile, and run Java programs independently
  • Understanding of basic exception handling with try-catch in Java
  • No prior experience with multithreading or concurrency is required

Description

This course contains the use of artificial intelligence.

Modern software does not wait around. Users expect instant responses, servers handle thousands of requests simultaneously, and data pipelines crunch millions of records in parallel. If your Java programs are still doing everything one step at a time, you are leaving performance on the table and falling behind the curve. Concurrency and multithreading are no longer optional skills for Java developers — they are the difference between applications that scale gracefully and applications that buckle under pressure. Understanding how to write thread-safe, concurrent Java code is one of the most valuable skills you can add to your toolkit, and this course gives you exactly that.


This course takes you on a structured journey through Java concurrency, starting with the fundamentals of thread creation, lifecycle management, and scheduling before diving into the critical topic of shared state and synchronization. You will learn how race conditions corrupt data and then master the tools that prevent them, including the synchronized keyword, volatile fields, atomic variables, ReentrantLock, and ReadWriteLock. From there, you will level up to Java's powerful higher-level concurrency utilities: thread pools with ExecutorService, Callable and Future for result-bearing tasks, scheduled executors for timed operations, coordination tools like CountDownLatch and CyclicBarrier, thread-safe collections like ConcurrentHashMap, and the expressive asynchronous pipelines enabled by CompletableFuture.


This course is designed for Java developers who are comfortable with the basics of the language and ready to tackle the challenges of concurrent programming. Whether you are a backend developer building high-throughput services, a software engineer preparing for technical interviews where concurrency questions are notoriously common, or a self-taught programmer ready to move beyond single-threaded thinking, you will walk away with practical skills you can apply immediately. Every concept is demonstrated through self-contained Java code that you can run, modify, and experiment with on your own machine.


What sets this course apart is its relentless focus on hands-on, code-driven learning. There are no abstract lectures about theory with no payoff — every single topic is demonstrated with a working Java program that produces real console output you can see and reason about. You will not just learn what a deadlock is; you will create one, watch your program freeze, and then fix it. That is the kind of learning that sticks. Enroll now and start writing Java code that does more, faster, and safely.

Who this course is for:

  • Java developers ready to move beyond single-threaded programming and build concurrent applications
  • Backend engineers who need to write high-throughput, thread-safe Java services
  • Software engineers preparing for technical interviews that cover concurrency and multithreading
  • Computer science students looking for practical, code-driven concurrency training in Java
  • Self-taught programmers who understand Java basics and want to level up to intermediate skills