
Learn threading and parallel programming in Java using modern techniques and syntax. Build real-world Java threading applications with lambdas and streams for beginners and experienced developers.
Discover Java threads and multithreading, splitting tasks to run in parallel on multiple cores to boost performance. Learn single versus multi-threading, and the roles of user and daemon threads.
Install Java on Windows and choose a version above Java 8. Download the JDK, accept the license, run the installer, and complete the setup.
Download and install IntelliJ IDEA on Windows, run the installer, and complete the setup by creating a desktop icon and associating Java.
Install the Java Development Kit on a Mac by downloading from Oracle, accepting the license, running the installer, entering your password, and confirming Java is installed.
Install IntelliJ IDEA Community Edition on Mac by downloading it, dragging it to the Applications folder, choosing do not import settings, selecting the light UI, and start using the IDE.
Configure IntelliJ IDEA for easier Java development by enabling auto import on the fly, optimizing imports, enabling line numbers, and adjusting code folding and related settings.
Import code from GitHub by cloning the repositories for the threading project and the lambda expression, then open them and start coding.
Show sequential processing in Java by simulating a supervisor and two workers executing tasks in order. Implement a supervisor class with two worker classes, looping 0–9 with 400 ms pauses.
Launch two worker threads to execute tasks in parallel using Java's Thread class, overriding run, and starting the threads to show parallelism with a 1–10 loop and sleeping 100 ms.
Learn that lambda expressions in Java are anonymous functions, used to implement functional interfaces with a single abstract method, with type inference by the Java 8+ compiler.
Explore the first lambda expression in Java by implementing a hello world interface both traditionally and with a lambda, demonstrating how to return 'Hello World' and print it.
Explore how lambda expressions simplify Java code by removing boilerplate in functional interfaces, with examples like increment by 5 and string concatenation, and see automatic return type inference.
Demonstrate runnable implementations using traditional approaches and lambda expressions, run threads to sum ten numbers, and compare concise lambda syntax with the standard approach.
Learn to implement a callable using a lambda expression to sum numbers from 0 to 5000, run two callables with an executor service, and verify the results with futures.
explore parallel processing using the runnable interface and two worker threads to sum 5000 numbers, verify totals, then simplify with lambda expressions and synchronize access for correctness.
Explore how the join method lets a thread wait for others to finish, including timeout and interruption handling, illustrated by summing 5000 numbers in parallel.
Learn how volatile prevents thread-local caching by reading from main memory to improve visibility across threads. Understand that volatile does not guarantee atomicity and may still require synchronization.
Explore how deadlock occurs when two threads wait on each other's locks, and how livelock differs, illustrated with bank transfer scenarios and resource locking.
Explore how Java synchronization prevents interference in shared resources by enforcing mutual exclusion, using synchronized methods and blocks, static synchronization, and intrinsic locks with wait/notify.
Demonstrates synchronized methods to prevent race conditions in a fast food restaurant simulation, tracking the last customer and total burgers sold while modeling long-running prep and timing.
Explore how synchronized blocks optimize Java multithreading by replacing a synchronized method, measuring performance gains when long-running tasks are moved outside the synchronized block while keeping correct burger counts.
Learn how wait, notify, and notifyAll coordinate threads on a shared course object, releasing locks and waking waiting students to signal course completion in Java multithreading.
Compare lock-based synchronization with the synchronized keyword, using try lock, reentrant lock, fairness, and timeouts, illustrated via a bank transfer example.
Explore how a semaphore controls access to a shared resource in a Java multithreading scenario, using acquire and release to bound a collection and limit concurrent database connections.
Learn how an executor manages and executes tasks using a thread pool, selecting threads, queuing work, and employing fixed, scheduled, single, and work stealing executors with submit, execute, and invoke.
Explore using an executor service with runnable and callable tasks, comparing execute and submit, handling futures, and retrieving results from multiple tasks while illustrating blocking and non-blocking behavior.
Explore how callable and future enable parallel computation by returning values, using an executor service to run two callables that sum ranges of numbers, and retrieve results with future.get.
Learn countdown latch synchronization to coordinate two parallel tasks that sum numbers from 0 to 5000, using an executor service and futures, with a wait-for-zero until completion.
Explore Java cyclic barrier synchronization, where threads wait at a barrier before proceeding, with reset capability, demonstrated by a three-step sum using the executor service and futures.
Explore blocking queue behavior in Java multithreading, showing how producers and consumers synchronize and how queue operations block or time out. Cover array blocking queue, linked blocking queue, priority blocking queue, delay queue, and synchronous queues.
Explore array blocking queue concepts with fixed capacity and blocking put and take operations. Learn first-in, first-out ordering, optional fairness, and a producer-consumer example demonstrating blocking when full or empty.
Learn how the unbounded blocking delay queue handles delayed elements, implementing a delay task with getDelay and compareTo, and using a producer and consumer pattern with put and take.
This lecture introduces the linked blocking queue, a linked fifo structure with head and tail behavior, and demonstrates adapting a blocking queue example to implement it, noting throughput and inconsistency.
Explore implementing a priority blocking queue for a producer–consumer pattern, using natural ordering, blocking take and put operations, and dynamic capacity growth to manage names or items.
Explore how a synchronous queue blocks on each insert until a consumer removes it, enabling a no internal capacity handoff in a producer–consumer Java example.
Explore the differences between traditional and concurrent collections, highlighting synchronized vs non-synchronized classes, locking overhead, and how copy-on-write and segmenting improve multi-threaded performance, avoiding the concrete modification exception.
Explore concurrent hash maps for thread-safe, high performance maps with segment locking, compare with hash table and synchronized map, and implement a token generation demo with concurrent reads and writes.
Explore navigable maps by building a navigable map with views for head map, tail map, and sub map, and examine range-based key filtering and view outputs.
Master the fork-join framework to split work across cores, join results, and manage parallelism with Java RecursiveTask and RecursiveAction.
Explore a fork join parallel computing approach to sum a large list in parallel, splitting tasks recursively, forking subtasks, and joining results with a threshold of five elements.
explain the dining philosophers problem with five philosophers around a round table and forks between them, and implement a java multithreading solution using locks and synchronization for eating and thinking.
Master Java multithreading presents a dining philosopher problem solution using synchronized blocks, implementing a Philosopher class with left and right forks and a thinking and eating loop run by threads.
Learn how Java streams, introduced in Java 8, provide an abstract layer over collections to build parallel pipelines with map, filter, sort, and collect.
Create a stream-based example to map instructors' names to their online courses, filtering for online instructors with more than 10 years of experience using predicates, filters, and collectors.
Demonstrate how streams execute from intermediate filters to terminal collects, revealing the internal chain and why streams cannot be rewound, with debugging to visualize the hash map results.
Compare collections and streams in Java, showing how collections store and modify data, while streams provide lazy, one-time traversal built from collections. Trigger processing with a terminal operation.
Discover two approaches to debugging stream operations in Java: use the debugger's trace and chain tool with breakpoints, and leverage the peak method to inspect elements at each stage.
Explore nomadic streams and the three nomadic extremes, including primitive integer streams, the longest stream of double values, and a revenue stream of primitive doubles in Java multithreading.
Explore creating integer streams with IntStream using of, range, and rangeClosed, including 1 to 5 and 0 to 4 sequences, and a random generator with bound 10.
Explore how to generate Java long streams using methods like range, random, and iterative patterns, print sequences such as even numbers and restricted outputs with limits.
Master several ways to generate a double stream in Java, including double stream from provided values, long stream range via asDoubleStream, and random numbers with a limit.
Calculate sum, min, max, and average using a numeric stream in Java; demonstrates optional integers and optional doubles, and prints the results for numbers 0 through 1000.
Demonstrate boxing and unboxing by converting primitive ints to Integer objects for lists and streams, then unbox with reduce or map to integer to compute sums.
Explore how to use Java streams' mapToObject, mapToLong, and mapToDouble to map elements into objects, longs, and doubles, with practical examples generating random tokens and IDs.
******* Course Overview *******
Welcome to this Amazing course on Java Multi-threading programming.
The course will guide you through the important aspects of multi-threading in java.
The course will provide an in-depth understanding of Threading and Parallel programming in java using modern java techniques and syntax
We will be building real world java threading applications using modern java technology like Lambda's and Streams
The course is for beginners are well as for experienced programmers
Each of my courses come with:
Amazing Hands-on Step By Step Learning Experiences
Real Implementation Experience
The below are the list of modules covered in this course.
***************Course details**********************
Section 1:Introduction
Step-01: Introduction
Step-02: Thread Introduction
Step-03: Java Development Kit Installation Overview
Step-04: Installing Intellij IDEA for Windows
Step-05: IntelliJ IDEA Configuration
Step-04: Git Repository Link
Step-05: Development Environment Setup - Import Code
Section 2:Multi-Threading Basics
Step-01: Sequential Processing
Step-02: Parallel Programming with Thread Class
Section 3:Lambda Expressions
Step-01: What is Lambda
Step-02: Lambda Expression (Part 1)
Step-03: Lambda Expression (Part 2)
Step-04: Runnable Example With Lambda
Step-05: Comparator Example With Lambda
Step-06: Callable Example With Lambda
Section 4:Multi-Threading Basics (Part 2)
Step-01: Parallel Programming with Runnable Interface
Step-02: Joins
Step-02: Volatile
Step-04: DeadLock And LiveLock
Step-05: Synchronization
Step-06: Synchronized Methods
Step-07: Synchronized Blocks
Step-08: Wait, Notify, NotifyAll
Step-09: Locks
Step-10 Semaphore
Step-11: Executor
Step-11: Executor With Runnable and Callable
Step-13: Callable & Future
Section 5:Concurrent Utilities
Step-01: CountDownLatch
Step-02: Cyclic Barrier
Step-03: Blocking Queue
Step-04: Array Blocking Queue
Step-05: Delay Queue
Step-06: Linked Blocking Queue
Step-07: Priority Blocking Queue
Step-08: Synchronous Queue
Section 6:Concurrent Collections
Step-01: Difference b/w Traditional & Concurrent Collections
Step-02: Concurrent HashMap
Step-03 Navigable Map
Section 7:Functional Interfaces and Lambdas (Lambda Part 2)
Step-01: Functional Interfaces
Step-02: Consumer Functional Interface (Part 1)
Step-03: Consumer Functional Interface (Part 2)
Step-04: IntConsumer, LongConsumer, DoubleConsumer
Step-04: BiConsumer Functional Interface
Step-05: BiConsumer Functional Interface (Part 2)
Step-06: Predicate Functional Interface (Part 1)
Step-07: Predicate Functional Interface (Part 2)
Step-08: IntPredicate, LongPredicate, DoublePredicate
Step-09: Predicate & BiConsumer
Step-10: BiPredicate Functional Interface
Step-11: Function (Part 1)
Step-12: Function (Part 2)
Step-13: BiFunction
Step-14: Unary Operator
Step-15: Binary Operator
Step-16: Supplier
Step-17: Method Reference (::)
Step-18: Examples of Method Reference
Step-19: Convert to Method Reference
Step-20: Constructor Reference
Section 8:Lambda Variable Scope
Step-01: Variable Scope, Final & Effectively Final
Section 9: RealWorld MultiThreading Example Using Lambda
Step-01: Bank Transfer Example
Section 10:Stream
Step-01: Stream Introduction (Part 1)
Step-02: Stream Introduction (Part 2)
Step-03: Inside Streams
Step-04: Collections vs Streams
Step-05: Debugging Stream
Section 11:Stream Operations
Step-01: map()
Step-02: flatMap()
Step-03: distinct(), count(), sorted(), allMatch()...
Step-04: Customized sort using comparator
Step-05: filter()
Step-06: reduce() (Part 1)
Step-07: reduce (Part 2)
Step-08: map + filter + reduce
Step-09: max() with stream and reduce
Step-10: min() with stream and reduce
Step-11: limit() and skip()
Step-12: findAny() and findFirst()
Section 12: Stream Generators
Step-01: Generating Stream with of(), iterate(), generate()
Section 13:Numeric Streams
Step-01: Introduction
Step-02: IntStream
Step-03: LongStream
Step-04: DoubleStream
Step-04: sum(), max(), min(), average()
Step-05: Boxing, Unboxing
Step-06: mapToObj(), mapToLong, mapToDouble()
Section 14:Collectors Operations
Step-01: joining
Step-02: counting()
Step-03: mapping()
Step-04: minBy(), maxBy()
Step-05: summingInt(), averagingInt()
Step-06: groupingBy (Part 1)
Step-07: groupingBy (Part 2)
Step-08: groupingBy (Part 3)
Step-10: maxBy(), minBy(), collectingAndThen(), summarizingInt()
Step-11: partitioningBy()
Section 15:Parallel Streams
Step-01: Introduction to Parallel Streams
Step-02: Sequential vs Parallel Performance (Part 1)
Step-03: Sequential vs Parallel Performance (Part 2)
Section 16:Fork-Join
Step-01: Fork-Join Framework Introduction
Step-02: Fork Join Example
Section 17:References
Section 18:Dining Philosopher Problem
Step-01: Dining Philosopher Problem Solution