杰瑞科技汇

Java线程run()与start()有何区别?

Of course! The java.lang.Thread.run() method is a fundamental concept in Java concurrency. Let's break it down in detail, from the basic definition to best practices and common pitfalls.

Java线程run()与start()有何区别?-图1
(图片来源网络,侵删)

The Core Definition: What is Thread.run()?

In Java, every Thread object has a public void run() method. This method contains the code that you want to execute in that separate thread of execution.

Key Point: The run() method is not special. It's just like any other public method in a Java class. It has no special properties or syntax.

The Two Ways to Use run()

There are two distinct ways to interact with the run() method, and understanding the difference between them is crucial.


Method 1: Directly Calling run()

If you create a Thread object and then call its run() method directly from your main thread, no new thread is created. The code inside run() simply executes on the current thread (the one that called it).

Java线程run()与start()有何区别?-图2
(图片来源网络,侵删)

Example:

class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("Running in a thread: " + Thread.currentThread().getName());
        System.out.println("This is the task's code.");
    }
}
public class DirectRunExample {
    public static void main(String[] args) {
        MyTask task = new MyTask();
        Thread thread = new Thread(task);
        System.out.println("Main thread is about to call run() directly.");
        // This is a METHOD CALL, not starting a new thread
        thread.run(); 
        System.out.println("Main thread has finished calling run().");
    }
}

Output:

Main thread is about to call run() directly.
Running in a thread: main
This is the task's code.
Main thread has finished calling run().

Analysis: Notice the thread name is main. The run() method executed synchronously on the main thread. The program did not perform any concurrent execution. This is a very common mistake for beginners.


Method 2: Starting a Thread with start()

To achieve true concurrency, you must use the start() method.

When you call thread.start():

  1. The Java Virtual Machine (JVM) creates a new thread.
  2. The JVM then calls the run() method of your Thread object on this newly created thread.

This is the correct way to run code in parallel.

Example:

class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("Running in a thread: " + Thread.currentThread().getName());
        System.out.println("This is the task's code.");
    }
}
public class StartThreadExample {
    public static void main(String[] args) {
        MyTask task = new MyTask();
        Thread thread = new Thread(task);
        System.out.println("Main thread is about to call start().");
        // This tells the JVM to create a new thread and execute its run() method
        thread.start(); 
        System.out.println("Main thread has finished calling start().");
    }
}

Possible Output (order may vary):

Main thread is about to call start().
Main thread has finished calling start().
Running in a thread: Thread-0
This is the task's code.

Analysis:

  • The main thread continues its execution immediately after start() returns, without waiting for the new thread to finish.
  • The code inside run() is executed on a different thread (named Thread-0 by default).
  • This demonstrates concurrent execution.

The Relationship: Runnable vs. Thread.run()

The run() method is part of the java.lang.Runnable interface. A Thread object's run() method is designed to execute the code of whatever Runnable object it has been given.

Let's look at the source code of java.lang.Thread (simplified):

public class Thread implements Runnable {
    // ... other fields and methods ...
    // The Runnable object whose run() method will be called
    private Runnable target;
    // This is the run() method of the Thread class itself
    @Override
    public void run() {
        if (target != null) {
            // If a Runnable was provided to the constructor,
            // the Thread's run() method simply calls the target's run() method.
            target.run();
        }
    }
    // Constructor that takes a Runnable
    public Thread(Runnable target) {
        // ... initialization ...
        this.target = target;
    }
    // ... other constructors ...
}

This is the standard and most flexible way to create threads:

  1. You create a class that implements Runnable. This class contains your task logic in its run() method.
  2. You pass an instance of your Runnable to the Thread constructor.
  3. When thread.start() is called, Thread.run() executes, which in turn calls yourRunnable.run().

Modern Approach: ExecutorService (Best Practice)

While extending Thread or implementing Runnable is the classic way, modern Java applications use the java.util.concurrent package, specifically the ExecutorService framework.

Why?

  • Resource Management: It manages a pool of threads, avoiding the overhead of creating and destroying threads for every task.
  • Simplified API: It provides high-level methods like execute(), submit(), and shutdown().
  • Future and Results: It allows you to get results from tasks using Future objects.

Example using ExecutorService:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("Executing task in thread: " + Thread.currentThread().getName());
    }
}
public class ExecutorServiceExample {
    public static void main(String[] args) {
        // Create a thread pool with 2 threads
        ExecutorService executor = Executors.newFixedThreadPool(2);
        // Submit 5 tasks to the executor
        for (int i = 0; i < 5; i++) {
            executor.execute(new MyTask());
        }
        // Shutdown the executor, which will wait for tasks to complete
        executor.shutdown();
    }
}

Output:

Executing task in thread: pool-1-thread-1
Executing task in thread: pool-1-thread-2
Executing task in thread: pool-1-thread-1
Executing task in thread: pool-1-thread-2
Executing task in thread: pool-1-thread-1

(The order of execution depends on which thread in the pool picks up the task next.)

Summary Table

Method What it Does When to Use Key Difference
thread.run() Executes the task's code on the current thread. Almost never. This is usually a mistake. Does not create a new thread.
thread.start() Creates a new thread and then calls thread.run() on that new thread. The classic way to start a new thread of execution. Creates a new thread.
executor.execute() Submits a task to a thread pool for execution. The modern, preferred way for most applications. Manages a pool of threads for better performance and control.

Key Takeaways

  1. run() is the code, start() is the trigger. run() contains the logic; start() tells the JVM to run that logic in a new thread.
  2. Never call run() directly if you intend to use multithreading. Always use start().
  3. The Runnable interface is a flexible way to define a task that can be run in a thread.
  4. For production code, prefer using ExecutorService over manually creating and managing Thread objects. It's safer, more efficient, and easier to work with.
分享:
扫描分享到社交APP
上一篇
下一篇