Runnable
InterfaceThread
ClassA thread is an independent path of execution within a program. Java provides a built - in mechanism for creating and managing threads. When a class is converted into a thread, it can run concurrently with other threads, sharing the same resources in a controlled manner.
Concurrency is the ability of a program to handle multiple tasks at the same time. By converting a class into a thread, we can achieve concurrency, which can significantly improve the performance of an application, especially when dealing with I/O - bound or CPU - intensive tasks.
When performing operations such as reading from or writing to a file, network sockets, or databases, the program often has to wait for the I/O device to respond. By converting the class responsible for these operations into a thread, the main thread can continue to execute other tasks while waiting for the I/O operation to complete.
Some tasks, like background data processing or monitoring, can be run in a separate thread. For example, a program that needs to continuously monitor system resources can have a dedicated thread for this task, leaving the main thread to handle user interactions.
Runnable
InterfaceThe Runnable
interface is a functional interface in Java that contains a single abstract method run()
. When a class implements the Runnable
interface, it provides an implementation for the run()
method, which contains the code that will be executed when the thread starts.
// Define a class that implements the Runnable interface
class MyRunnable implements Runnable {
@Override
public void run() {
// Code to be executed in the thread
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
// Simulate some work
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableExample {
public static void main(String[] args) {
// Create an instance of the MyRunnable class
MyRunnable myRunnable = new MyRunnable();
// Create a Thread object and pass the MyRunnable instance to its constructor
Thread thread = new Thread(myRunnable);
// Start the thread
thread.start();
}
}
In this example, the MyRunnable
class implements the Runnable
interface. An instance of MyRunnable
is created and passed to the Thread
constructor. Then, the start()
method is called on the Thread
object to start the execution of the thread.
Thread
ClassAnother way to convert a class into a thread is by extending the Thread
class. When a class extends the Thread
class, it can override the run()
method to define the code that will be executed in the thread.
// Define a class that extends the Thread class
class MyThread extends Thread {
@Override
public void run() {
// Code to be executed in the thread
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
// Simulate some work
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
// Create an instance of the MyThread class
MyThread myThread = new MyThread();
// Start the thread
myThread.start();
}
}
In this example, the MyThread
class extends the Thread
class. An instance of MyThread
is created, and the start()
method is called to start the execution of the thread.
start()
One common mistake is to call the run()
method directly instead of the start()
method. When the run()
method is called directly, it is executed in the current thread, not in a new thread.
class WrongExample implements Runnable {
@Override
public void run() {
System.out.println("Running in the wrong way");
}
}
public class WrongUsage {
public static void main(String[] args) {
WrongExample wrongExample = new WrongExample();
// This will run in the main thread, not a new thread
wrongExample.run();
}
}
When multiple threads access and modify shared resources, it can lead to race conditions. For example, if two threads try to increment a shared variable at the same time, the result may be inconsistent.
class SharedResource {
public static int counter = 0;
}
class IncrementThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
SharedResource.counter++;
}
}
}
public class RaceConditionExample {
public static void main(String[] args) throws InterruptedException {
IncrementThread incrementThread = new IncrementThread();
Thread thread1 = new Thread(incrementThread);
Thread thread2 = new Thread(incrementThread);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Counter value: " + SharedResource.counter);
}
}
In this example, the counter
variable is a shared resource. The final value of the counter
may be less than 2000 due to race conditions.
Runnable
InterfaceIt is generally recommended to implement the Runnable
interface rather than extending the Thread
class. This is because Java does not support multiple inheritance, and by implementing the Runnable
interface, a class can still extend other classes if needed.
To avoid race conditions, use synchronization mechanisms such as synchronized
blocks or Lock
objects when accessing and modifying shared resources.
class SynchronizedResource {
public static int counter = 0;
public static synchronized void increment() {
counter++;
}
}
class SynchronizedIncrementThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
SynchronizedResource.increment();
}
}
}
public class SynchronizedExample {
public static void main(String[] args) throws InterruptedException {
SynchronizedIncrementThread incrementThread = new SynchronizedIncrementThread();
Thread thread1 = new Thread(incrementThread);
Thread thread2 = new Thread(incrementThread);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Counter value: " + SynchronizedResource.counter);
}
}
Converting a class into a thread in Java is a fundamental technique for achieving concurrency and improving the performance of applications. By understanding the core concepts, typical usage scenarios, common pitfalls, and best practices, developers can effectively use threads in their Java programs. Whether implementing the Runnable
interface or extending the Thread
class, proper handling of shared resources and correct use of thread - starting methods are crucial for writing robust multi - threaded applications.
Runnable
interface or extending the Thread
class?A1: Implementing the Runnable
interface is generally better because it allows a class to extend other classes if needed, as Java does not support multiple inheritance.
start()
method instead of the run()
method?A2: The start()
method creates a new thread and calls the run()
method in that new thread. If you call the run()
method directly, it will be executed in the current thread, not in a new thread.
A3: You can use try - catch blocks inside the run()
method to handle exceptions. If an uncaught exception occurs in a thread, it will terminate the thread, but you can also set an UncaughtExceptionHandler
for the thread to handle such cases.
This blog post should help you gain a deep understanding of converting a class into a thread in Java and apply this knowledge in real - world scenarios.