The ThreadFactory interface defined in the java.util.concurrent package is based on the factory design pattern. As its name suggests, it is used to create new threads on demand. Threads can be created in two ways:
1. Creating a class that extends the Thread class and then creating its objects.
Java
import java.io.*; class GFG { public static void main(String[] args) { // Creating a thread Thread thread = new CustomThread(); thread.start(); // Starting execution of the created // thread } } // Creating a class that extends the Thread class class CustomThread extends Thread { @Override public void run() { System.out.println( "This is a thread" ); } } |
This is a thread
2. Creating a class that implements the Runnable interface and then using its object to create threads.
Java
/*package whatever //do not write package name here */ import java.io.*; class GFG { public static void main(String[] args) { // Creating a Runnable object Runnable task = new Task(); // Creating a thread using the Runnable object Thread thread = new Thread(task); // Starting the execution of the created thread thread.start(); } } class Task implements Runnable { @Override public void run() { System.out.println( "This is a thread" ); } } |
This is a thread
However, ThreadFactory is another choice to create new threads. This interface provides a factory method that creates and returns new threads when called. This factory method takes a Runnable object as an argument and creates a new thread using it.
The Hierarchy of ThreadFactory
java.util.concurrent ↳ Interface ThreadFactory
Implementation of ThreadFactory interface
Since ThreadFactory is an interface, the factory method defined inside it has to be implemented first in order to be used. Here is the simplest implementation of the ThreadFactory interface :
Java
import java.util.concurrent.ThreadFactory; import java.io.*; class CustomThreadFactory implements ThreadFactory { // newThread is a factory method // provided by ThreadFactory public Thread newThread(Runnable command) { return new Thread(command); } } |
Now, we can create objects of the CustomThreadFactory class and use its newThread(Runnable command) method to create new threads on demand. In the above implementation, the newThread method just creates a new thread by calling the Thread constructor which takes a Runnable command as the parameter.
There are many classes(such as ScheduledThreadPoolExecutor , ThreadPoolExecutor etc.) that use thread factories to create new threads when needed. Those classes have constructors that accept a ThreadFactory as argument. If any custom ThreadFactory is not given then they use the default implementation of ThreadFactory interface.
The Executors class in java.util.concurrent package provides Executors.defaultThreadFactory() static method that returns a default implementation of ThreadFactory interface.
Example: Below example code demonstrates ThreadFactory interface.
Java
// Java code to demonstrate ThreadFactory interface import java.util.concurrent.ThreadFactory; import java.io.*; import java.util.ArrayList; class ThreadFactoryExample { public static void main(String[] args) { // Creating a CustomThreadFactory object CustomThreadFactory threadFactory = new CustomThreadFactory(); // Creating Runnable objects using the lambda // expression Runnable command1 = () -> System.out.println( "Command 1 executed" ); Runnable command2 = () -> System.out.println( "Command 2 executed" ); Runnable command3 = () -> System.out.println( "Command 3 executed" ); Runnable command4 = () -> System.out.println( "Command 4 executed" ); Runnable command5 = () -> System.out.println( "Command 5 executed" ); // Putting the commands in an ArrayList ArrayList<Runnable> array = new ArrayList<>( 5 ); array.add(command1); array.add(command2); array.add(command3); array.add(command4); array.add(command5); // creating threads and running them for (Runnable command : array) { threadFactory.newThread(command).start(); } // print the thread count System.out.println( "Total number of threads created using CustomThreadFactory = " + threadFactory.getCount()); } } // ThreadFactory class class CustomThreadFactory implements ThreadFactory { // stores the thread count private int count = 0 ; // returns the thread count public int getCount() { return count; } // Factory method @Override public Thread newThread(Runnable command) { count++; return new Thread(command); } } |
Command 1 executed Command 2 executed Command 4 executed Command 3 executed Command 5 executed Total number of threads created using CustomThreadFactory = 5
Why use ThreadFactory?
In the above example, the newThread(Runnable) factory method ultimately creates a new thread using the given Runnable command. Then why use ThreadFactory? We could directly create threads from the Runnable commands by calling the Thread constructor that we did in the newThread(Runnable) method. Here are some reasons,
- We can give the threads more meaningful custom names. It helps in analyzing their purposes and how they work.
- We can have the statistics about the created threads like the count of threads and other details. We can restrict the creation of new threads based on the statistics.
- We can set the daemon status of threads.
- We can set the thread priority.
- We can have all the features confined in one class.
Default Thread Factory
It is the default thread factory that is implemented by the Executors.defaultThreadFactory() static method. This default ThreadFactory is used by many classes (such as ScheduledThreadPoolExecutor, ThreadPoolExecutor etc.) when they are not given any custom ThreadFactory. Those classes create new threads using the default ThreadFactory. This default ThreadFactory creates all the new threads in the same ThreadGroup(A ThreadGroup represents a group of threads). All the created new threads are non-daemon with priority set to the smallest of Thread.NORM_PRIORITY and the maximum priority permitted in the ThreadGroup. The threads created by this default ThreadFactory are given names in the form of pool-N-thread-M (As examples, pool-1-thread-1, pool-1-thread-2, pool-2-thread-1 etc.) where N is the sequence number of this factory, and M is the sequence number of the threads created by this factory.
Example: The below example demonstrates how the default ThreadFactory can be used.
Java
// Java program to demonstrate default // ThreadFactory import java.io.*; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; class DefaultThreadFactoryExample { public static void main(String[] args) { // Default ThreadFactory ThreadFactory threadFactory = Executors.defaultThreadFactory(); for ( int i = 1 ; i < 10 ; i++) { // Creating new threads with the default // ThreadFactory Thread thread = threadFactory.newThread( new Command()); // print the thread names System.out.println( "Name given by threadFactory = " + thread.getName()); // run the thread thread.start(); } } } class Command implements Runnable { @Override public void run() { // Run some code } } |
Name given by threadFactory = pool-1-thread-1 Name given by threadFactory = pool-1-thread-2 Name given by threadFactory = pool-1-thread-3 Name given by threadFactory = pool-1-thread-4 Name given by threadFactory = pool-1-thread-5 Name given by threadFactory = pool-1-thread-6 Name given by threadFactory = pool-1-thread-7 Name given by threadFactory = pool-1-thread-8 Name given by threadFactory = pool-1-thread-9
Note the names of threads given by default ThreadFactory. It has created 9 threads and all the threads are in the same ThreadGroup. All the threads are created using the same ThreadFactory(so the names of the threads are in form of pool -1 -thread-M).
Example:
Java
// Java program to demonstrate ThreadFactory // using default implementation import java.io.*; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; class DefaultThreadFactoryExample { public static void main(String[] args) { for ( int i = 1 ; i < 10 ; i++) { // Default ThreadFactory ThreadFactory threadFactory = Executors.defaultThreadFactory(); // Creating new threads with the default // ThreadFactory Thread thread = threadFactory.newThread( new Command()); // print the thread name System.out.println( "Name given by threadFactory = " + thread.getName()); // start the thread thread.start(); } } } class Command implements Runnable { @Override public void run() { // Run some code } } |
Name given by threadFactory = pool-1-thread-1 Name given by threadFactory = pool-2-thread-1 Name given by threadFactory = pool-3-thread-1 Name given by threadFactory = pool-4-thread-1 Name given by threadFactory = pool-5-thread-1 Name given by threadFactory = pool-6-thread-1 Name given by threadFactory = pool-7-thread-1 Name given by threadFactory = pool-8-thread-1 Name given by threadFactory = pool-9-thread-1
Here, We have used 9 different default ThreadFactories(in each loop we are creating a new one!). So each thread is in different ThreadGroup and thus the threads are given name in form of pool-N-thread-1.
The default ThreadFactory implementation creates non-daemon threads with normal priority and gives names in form of pool-N-thread-M which contains no information about how they work and what they do. This creates lots of problems in debugging and other important purposes. However, this problem can be solved using a custom ThreadFactory which can give more meaningful names to the threads and can set the daemon and priority statuses.
Methods of ThreadFactory
METHOD |
DESCRIPTION |
---|---|
newThread(Runnable r) | Constructs a new Thread. |