杰瑞科技汇

java 线程 run start

核心区别一句话总结

  • start(): 启动一个新线程,并让这个新线程去执行 run() 方法中的代码。当前线程会继续执行,不会等待新线程结束。
  • run(): 只是一个普通的方法,如果直接调用它,它会在当前线程中执行,并不会创建新的线程。

详细解释

start() 方法

当你调用一个线程对象的 start() 方法时,会发生以下事情:

java 线程 run start-图1
(图片来源网络,侵删)
  1. 创建新线程:JVM 会为这个线程对象创建一个新的执行栈(调用栈)。
  2. 调用 run():新线程会自动调用 run() 方法,并将 run() 方法中的代码作为它的任务来执行。
  3. 并发执行start() 方法会立即返回,而新线程会与调用 start() 的线程(通常是主线程)并发(并行或并发)地执行,主线程不会阻塞,会继续执行它自己的代码。

关键点start() 是“启动”一个线程的入口,它告诉 JVM:“请为我创建一个新的线程,并让它去执行 run() 方法里的任务”。

run() 方法

run() 方法是线程要执行的任务体,它本身就是一个普通的 Java 实例方法。

  • 直接调用:如果你直接 thread.run()run() 方法里的代码会在当前正在执行的线程(比如主线程)中按顺序执行,这没有创建任何新线程,代码仍然是单线程执行的。

代码示例

通过下面的例子,你可以非常直观地看到两者的区别。

示例 1:正确使用 start()(多线程)

class MyThread extends Thread {
    @Override
    public void run() {
        // 这是线程要执行的任务
        for (int i = 1; i <= 5; i++) {
            System.out.println("子线程 " + Thread.currentThread().getName() + " 正在运行,i = " + i);
            try {
                // 模拟耗时操作
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class StartExample {
    public static void main(String[] args) {
        System.out.println("主线程 " + Thread.currentThread().getName() + " 开始运行。");
        // 创建一个线程对象
        MyThread thread = new MyThread();
        // 调用 start() 方法启动线程
        thread.start();
        // 主线程继续执行自己的任务
        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程 " + Thread.currentThread().getName() + " 正在运行,i = " + i);
            try {
                Thread.sleep(300); // 主线程休眠时间不同,更容易观察交错执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("主线程 " + Thread.currentThread().getName() + " 运行结束。");
    }
}

可能的输出结果(顺序可能因线程调度而异):

java 线程 run start-图2
(图片来源网络,侵删)
主线程 main 开始运行。
子线程 Thread-0 正在运行,i = 1
主线程 main 正在运行,i = 1
子线程 Thread-0 正在运行,i = 2
主线程 main 正在运行,i = 2
子线程 Thread-0 正在运行,i = 3
主线程 main 正在运行,i = 3
子线程 Thread-0 正在运行,i = 4
主线程 main 正在运行,i = 4
子线程 Thread-0 正在运行,i = 5
主线程 main 正在运行,i = 5
主线程 main 运行结束。
子线程 Thread-0 正在运行,i = 5  // 子线程可能稍后才结束

分析

  1. 主线程开始,然后调用了 thread.start()
  2. start() 方法返回后,主线程和子线程 Thread-0 同时开始运行,它们各自的 for 循环被并发执行,输出结果交错出现,证明了多线程的特性。

示例 2:错误使用 run()(单线程)

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("子线程 " + Thread.currentThread().getName() + " 正在运行,i = " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class RunExample {
    public static void main(String[] args) {
        System.out.println("主线程 " + Thread.currentThread().getName() + " 开始运行。");
        MyThread thread = new MyThread();
        // 注意:这里直接调用了 run() 方法,而不是 start()
        thread.run();
        // 这部分代码会在线程 run() 方法执行完毕后才会执行
        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程 " + Thread.currentThread().getName() + " 正在运行,i = " + i);
        }
        System.out.println("主线程 " + Thread.currentThread().getName() + " 运行结束。");
    }
}

输出结果:

主线程 main 开始运行。
子线程 main 正在运行,i = 1
子线程 main 正在运行,i = 2
子线程 main 正在运行,i = 3
子线程 main 正在运行, i = 4
子线程 main 正在运行, i = 5
主线程 main 正在运行,i = 1
主线程 main 正在运行,i = 2
主线程 main 正在运行,i = 3
主线程 main 正在运行,i = 4
主线程 main 正在运行,i = 5
主线程 main 运行结束。

分析

  1. 主线程调用了 thread.run()
  2. run() 方法作为一个普通方法,在主线程中顺序执行,所有的 "子线程" 输出都来自主线程(Thread.currentThread().getName() 打印出 main)。
  3. 只有当 run() 方法执行完毕后,主线程才会继续执行它自己的 for 循环。
  4. 整个过程是单线程的,没有并发执行。

总结对比

特性 start() run()
功能 启动一个新线程,并使其进入就绪状态。 定义线程要执行的任务体。
执行者 新创建的线程 调用该方法的当前线程
是否创建新线程
调用方式 thread.start() thread.run()
程序行为 多线程并发执行。 单线程顺序执行。
类比 按下遥控器的“开机”按钮,电视开始播放节目。 你自己手动去操作电视的按钮,改变频道或音量。

最佳实践

在 Java 中,除了直接继承 Thread 类,更推荐使用 Runnable 接口Callable 接口(配合 FutureExecutorService)来创建线程,这样可以更好地解耦任务代码和线程管理代码。

java 线程 run start-图3
(图片来源网络,侵删)

使用 Runnable 的例子:

class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("任务正在由 " + Thread.currentThread().getName() + " 执行。");
    }
}
public class RunnableExample {
    public static void main(String[] args) {
        // 1. 创建任务
        MyTask task = new MyTask();
        // 2. 创建线程,并将任务交给线程
        Thread thread = new Thread(task);
        // 3. 启动线程(关键!)
        thread.start();
        System.out.println("主线程 " + Thread.currentThread().getName() + " 继续执行。");
    }
}

这个例子中,Runnable 对象 task 包含了任务逻辑,而 Thread 对象 thread 负责执行这个任务,调用 thread.start() 同样会创建新线程去执行 task.run()

记住这个黄金法则:要启动新线程,永远调用 start(),而不是 run()

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