杰瑞科技汇

Java Runnable与Thread有何区别?

Of course! Let's dive deep into creating threads in Java using the Runnable interface. This is a fundamental concept in Java concurrency.

Java Runnable与Thread有何区别?-图1
(图片来源网络,侵删)

What is a Thread?

Think of a program as a recipe. A thread is like a cook following that recipe. A single program can have multiple cooks (threads) working on different parts of the recipe at the same time. This is called multithreading.

  • Process: An instance of a running program. It has its own memory space.
  • Thread: The smallest unit of a process. It's a lightweight process that shares the memory space of its parent process. Multiple threads can run concurrently within a single program.

Why Use the Runnable Interface?

There are two primary ways to create a thread in Java:

  1. Extending the Thread class.
  2. Implementing the Runnable interface.

Using Runnable is generally the preferred and more flexible approach for these reasons:

  • Avoids Single Inheritance Limitation: Java does not support multiple inheritance of classes. If your class already extends another class (e.g., public class MyAnimation extends JPanel), you cannot also extend Thread. You can, however, implement Runnable in addition to extending another class.
  • Promotes Loose Coupling: The Runnable interface represents a "task" to be executed. By separating the task (Runnable) from the execution mechanism (Thread), your code becomes more modular and reusable. You can run the same task in different ways (e.g., in a new thread, in a thread pool, etc.) without changing the task's code.

The Core Concept: Runnable vs. Thread

It's crucial to understand the difference:

Java Runnable与Thread有何区别?-图2
(图片来源网络,侵删)
  • java.lang.Runnable: This is an interface, not a class. It defines a single method: public void run(). A Runnable object is a task—a piece of code you want to execute in a separate thread.
  • java.lang.Thread: This is a class. A Thread object is the execution mechanism. It takes a Runnable task and runs it.

The relationship is: A Thread executes a Runnable.


How to Create and Run a Thread with Runnable (The Classic Way)

Here is the step-by-step process:

Step 1: Create a class that implements the Runnable interface. Inside this class, you must implement the run() method. This is where you put the code you want to execute in the new thread.

Step 2: Create an instance of your Runnable class. This is just a regular object; no thread has been started yet.

Step 3: Create an instance of the Thread class. Pass your Runnable object to the Thread's constructor.

Step 4: Call the start() method on the Thread object. This is the most important step. start() tells the Java Virtual Machine (JVM) to create a new thread and execute the run() method of your Runnable object in that new thread.

⚠️ Important: Do NOT call the run() method directly! If you do, the code will execute in the current thread, not a new one. start() is what schedules the thread for execution.


Code Example

Let's see a simple example. We'll create two threads that count to five, demonstrating that they run concurrently.

// Step 1: Create a class that implements Runnable
class MyTask implements Runnable {
    private String threadName;
    public MyTask(String name) {
        this.threadName = name;
    }
    @Override
    public void run() {
        try {
            for (int i = 1; i <= 5; i++) {
                System.out.println(threadName + " count: " + i);
                // Sleep for a bit to simulate work and let other threads run
                Thread.sleep(500); // 500 milliseconds
            }
        } catch (InterruptedException e) {
            System.out.println(threadName + " interrupted.");
        }
        System.out.println(threadName + " finished.");
    }
}
// Main class to run the example
public class RunnableExample {
    public static void main(String[] args) {
        System.out.println("Main thread started.");
        // Step 2: Create instances of the Runnable task
        MyTask task1 = new MyTask("Thread-A");
        MyTask task2 = new MyTask("Thread-B");
        // Step 3: Create Thread objects, passing the Runnable tasks
        Thread thread1 = new Thread(task1);
        Thread thread2 = new Thread(task2);
        // Step 4: Start the threads
        thread1.start();
        thread2.start();
        // The main thread continues its execution
        try {
            // Main thread waits for thread1 and thread2 to finish
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            System.out.println("Main thread interrupted.");
        }
        System.out.println("Main thread finished.");
    }
}

Expected Output (Order may vary due to concurrency):

Main thread started.
Thread-A count: 1
Thread-B count: 1
Thread-A count: 2
Thread-B count: 2
Thread-A count: 3
Thread-B count: 3
Thread-A count: 4
Thread-B count: 4
Thread-A count: 5
Thread-B count: 5
Thread-A finished.
Thread-B finished.
Main thread finished.

Notice how both Thread-A and Thread-B are interleaving their output, proving they are running at the same time.


The Modern Way: Using Lambda Expressions (Java 8+)

Since Runnable is a functional interface (it has only one abstract method, run), you can use a lambda expression to make your code much more concise and readable.

You can skip creating a separate MyTask class entirely.

public class RunnableLambdaExample {
    public static void main(String[] args) {
        System.out.println("Main thread started.");
        // Using a lambda expression to define the task
        Thread thread1 = new Thread(() -> {
            try {
                for (int i = 1; i <= 3; i++) {
                    System.out.println("Lambda-Thread count: " + i);
                    Thread.sleep(300);
                }
            } catch (InterruptedException e) {
                System.out.println("Lambda-Thread interrupted.");
            }
            System.out.println("Lambda-Thread finished.");
        });
        thread1.start();
        System.out.println("Main thread continues while the new thread runs...");
    }
}

This is the most common and idiomatic way to create simple threads in modern Java.


Key Methods of the Thread Class

  • start(): Creates a new thread and calls the run() method on it.
  • run(): The method containing the code for the thread. It's called by start().
  • sleep(long millis): Pauses the currently executing thread for the specified number of milliseconds. It's a static method.
  • join(): Waits for the thread on which it's called to terminate. This is useful for coordinating threads.
  • interrupt(): Interrupts a thread. It's a polite way to ask a thread to stop what it's doing. The thread should periodically check its interrupted status (e.g., in a loop with Thread.currentThread().isInterrupted()).

Summary: Runnable vs. extends Thread

Feature implements Runnable extends Thread
Flexibility High. Can extend another class. Low. Cannot extend another class.
Design Preferred. Separates task from execution mechanism. Tightly couples the task to the thread.
Syntax Requires creating a Thread object and passing the Runnable to it. Simply create an instance and call start().
Modern Java Works perfectly with lambda expressions. Can also use lambdas, but the design is less flexible.

Conclusion: For almost all new Java code, prefer implementing Runnable, especially when using lambda expressions. It leads to more flexible, maintainable, and object-oriented designs.

分享:
扫描分享到社交APP
上一篇
下一篇