Java 8 introduced lambda expressions, making it easier to create threads by providing a concise implementation of the Runnable functional interface. Instead of creating anonymous classes, lambda expressions allow developers to define thread logic in a cleaner and more readable way.
- Eliminate the need for anonymous inner classes while creating threads.
- Make multithreaded code shorter, cleaner, and easier to maintain.
- Commonly used with the Executor framework, thread pools, and asynchronous programming.
Syntax:
( ) -> {
// thread logic
};
Steps to Create a Thread Using a Lambda Expression
Creating a thread using a lambda expression involves the following steps:
- Create a lambda expression that implements the run() method of the Runnable interface.
- Pass the Runnable object to the Thread constructor.
- Call the start() method to create and execute the new thread.
Example: Creating a Single Thread Using a Lambda Expression
In this example, a lambda expression provides the implementation of the run() method. The lambda is assigned to a Runnable reference, which is then passed to the Thread constructor. Calling start() executes the thread.
public class Test {
public static void main(String[] args)
{
// Creating Lambda expression for run() method in
// functional interface "Runnable"
Runnable myThread = () ->
{
// Used to set custom name to the current thread
Thread.currentThread().setName("myThread");
System.out.println(
Thread.currentThread().getName()
+ " is running");
};
// Instantiating Thread class by passing Runnable
// reference to Thread constructor
Thread run = new Thread(myThread);
// Starting the thread
run.start();
}
}
Output
myThread is running
Explanation:
- The lambda implements the run() method.
- A new Thread object is created using the Runnable.
- Calling start() begins thread execution and prints the thread name.
Example: Running Multiple Threads Using the Same Lambda Expression
The same lambda expression is shared by two different Thread objects. Each thread executes the same task independently, demonstrating code reuse with lambda expressions.
public class Test {
public static void main(String[] args)
{
Runnable basic = () ->
{
String threadName
= Thread.currentThread().getName();
System.out.println("Running common task by "
+ threadName);
};
// Instantiating two thread classes
Thread thread1 = new Thread(basic);
Thread thread2 = new Thread(basic);
// Running two threads for the same task
thread1.start();
thread2.start();
}
}
Output
Running common task by Thread-1 Running common task by Thread-0
Note: The execution order may vary because thread scheduling is managed by the JVM and operating system.
Explanation:
- Both threads share the same Runnable implementation.
- Each thread executes independently.
- The order of execution is non-deterministic.
Example: Performing Multiple Tasks Using Lambda Expressions
This example creates two separate lambda expressions: one for playing a game and another for playing music. Each lambda is executed in its own thread, allowing both tasks to run concurrently.
import java.util.Random;
// This is a random player class with two functionalities
// playGames and playMusic
class RandomPlayer {
public void playGame(String gameName)
throws InterruptedException
{
System.out.println(gameName + " game started");
// Assuming game is being played for 500
// milliseconds
Thread.sleep(500); // this statement may throw
// interrupted exception, so
// throws declaration is added
System.out.println(gameName + " game ended");
}
public void playMusic(String trackName)
throws InterruptedException
{
System.out.println(trackName + " track started");
// Assuming music is being played for 500
// milliseconds
Thread.sleep(500); // this statement may throw
// interrupted exception, so
// throws declaration is added
System.out.println(trackName + " track ended");
}
}
public class Test {
// games and tracks arrays which are being used for
// picking random items
static String[] games
= { "COD", "Prince Of Persia", "GTA-V5",
"Valorant", "FIFA 22", "Fortnite" };
static String[] tracks
= { "Believer", "Cradles", "Taki Taki", "Sorry",
"Let Me Love You" };
public static void main(String[] args)
{
RandomPlayer player
= new RandomPlayer(); // Instance of
// RandomPlayer to access
// its functionalities
// Random class for choosing random items from above
// arrays
Random random = new Random();
// Creating two lambda expressions for runnable
// interfaces
Runnable gameRunner = () ->
{
try {
player.playGame(games[random.nextInt(
games.length)]); // Choosing game track
// for playing
}
catch (InterruptedException e) {
e.getMessage();
}
};
Runnable musicPlayer = () ->
{
try {
player.playMusic(tracks[random.nextInt(
tracks.length)]); // Choosing random
// music track for
// playing
}
catch (InterruptedException e) {
e.getMessage();
}
};
// Instantiating two thread classes with runnable
// references
Thread game = new Thread(gameRunner);
Thread music = new Thread(musicPlayer);
// Starting two different threads
game.start();
music.start();
/*
*Note: As we are dealing with threads output may
*differ every single time we run the program
*/
}
}
Output
Let Me Love You track started Valorant game started Let Me Love You track ended Valorant game ended
Note: Since both threads execute concurrently, the output order may differ each time the program runs.
Explanation:
- Two separate lambda expressions implement different tasks.
- Each task runs in its own thread.
- The JVM schedules both threads independently.