Thread和Runnable、run和start的区别

本文深入探讨了Java中Thread与Runnable接口的区别,通过实例演示了两者在线程创建、资源共享及多线程编程中的不同表现,强调了Runnable在多线程资源共享方面的优势。

转载于:http://www.cnblogs.com/ycclmy/p/3148024.html

多线程可以通过两种方式来创建:

一、通过继承Thread类。

二、通过实现Runnable接口。

那么中两种方式到底有什么区别呢?那种方式更好些呢?

先看看几个简单的Demo:

Demo1

public class MyThread {

    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        t.start();
        t.start();
        t.start();
        t.start();
    }
}

class ThreadTest extends Thread {
    private int n = 10;

    @Override
    public void run() {
        while (n > 0) {
            System.out.println(Thread.currentThread().getName() + "  "
                    + n--);
        }
    }
}

在这里插入图片描述

运行后可以看出,其实只启动了一个线程,而且还抛异常了,这个在下面说。

我们修改一下代码:

Demo2

public class MyThread {

    public static void main(String[] args) {
        new ThreadTest().start();
        new ThreadTest().start();
        new ThreadTest().start();
        new ThreadTest().start();
    }
}

class ThreadTest extends Thread {
    private int n = 10;

    @Override
    public void run() {
        while (n > 0) {
            System.out.println(Thread.currentThread().getName() + "  "
                    + n--);
        }
    }
}


再次运行,发现这四个线程对象各自占有各自的资源,并不是同时完成统一任务。

我们可以得出结论:Thread类实际上无法达到资源共享的目的。

那么,Runnable接口能不能达到这一目的呢?

Demo3

public class MyThread {

    public static void main(String[] args) {
        RunnableTest r = new RunnableTest();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
    }
}class RunnableTest implements Runnable {
    private int n = 10;

    @Override
    public void run() {

        while (n > 0) {
            System.out.println(Thread.currentThread().getName() + "  "
                    + n--);

        }
    }
}

在这里插入图片描述

运行后我们发现,这四个线程同时完成了统一的任务,可以达到资源共享的目的

通过以上比较我们即可得出Thread与Runnable的区别:

Thread与Runnable的区别

1、Runnable适合于多个相同程序代码线程去处理统一资源的情况,把虚拟的cpu(线程)同程序的代码,数据有效分离,较好体现面向对象的编程的思想

2、Runnable可以避免由于java的单继承机制带来的局限。可以再继承其他类的同时,还能实现多线程的功能。

3、Runnable能增加程序的健壮性。代码能够被多个线程共享。

我们把Demo1的线程start()方法改成run()试试

public class MyThread {

    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        t.run();
        t.run();
        t.run();
        t.run();
    }
}

class ThreadTest extends Thread {
    private int n = 10;

    @Override
    public void run() {
        while (n > 0) {
            System.out.println(Thread.currentThread().getName() + "  "
                    + n--);
        }
    }
}

在这里插入图片描述

把Demo2的所有线程的start方法改成run试试

public class MyThread {

    public static void main(String[] args) {
        new ThreadTest().run();
        new ThreadTest().run();
        new ThreadTest().run();
        new ThreadTest().run();
    }
}

class ThreadTest extends Thread {
    private int n = 10;

    @Override
    public void run() {
        while (n > 0) {
            System.out.println(Thread.currentThread().getName() + "  "
                    + n--);
        }
    }
}

在这里插入图片描述

由此我们可以区别:

1、start()方法:启动一个线程,不能多次启动一个线程。

2、run()方法:在本线程内调用run()方法,可以重复多次调用。

3、用start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。

4、run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,要等待run方法体执行完毕后才可继续执行下面的代码。

转载于:http://www.cnblogs.com/ycclmy/p/3148024.html

我的总结
thread 和runnable
thread创建的线程不能共享 runnable创建的线程可以通过多次调用start()来达到资源共享,多个线程同时进行操作
run方法是调用线程内的run方法,可重复调用,但没有真正实现多线程,执行完之后需要等待
start方法是用来启动线程,无需等待run方法体代码执行完毕

<think>首先,用户的问题是:“我想了解thread.startthread.run区别 请问thread.startthread.run区别”。这是在询问JavaThread类的start()run()方法的区别。 从系统级指令中,我有几个关键点: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 结构清晰,逐步解决问题。 我需要参考提供的站内引用: - 引用[1]:讨论了JavaThreadstart()run()的区别,强调start()启动线程run()只是调用方法。 - 引用[2]:关于C#中Task.RunTask.Factory.StartNew的区别,但这是C#相关的,用户的问题是Java,所以我应该谨慎使用。 - 引用[3]:也是C#相关的,类似Task.RunTask.Factory.StartNew。 - 引用[4]:解释了Thread.start()run()的区别及原理,提到Runnable接口、线程状态等。 用户的问题是针对JavaThread类,所以我应该主要基于引用[1][4],因为它们直接相关。引用[2][3]是C#的,可能不适合Java上下文,但可以类比理解概念。 核心区别: - start()方法:启动一个新线程,使线程进入就绪状态,然后JVM调用run()方法在新线程中执行。 - run()方法:只是一个普通方法调用。如果直接调用run(),它会在当前线程中执行,而不是创建新线程。 从引用[1]:"t.start(); 该行代码相当于是启动线程,t.run(); 该行代码相当于是使用t这个类中的run方法而已." 从引用[4]:"Thread.start()启动线程,然后调用run()方法。直接调用run()不会创建新线程。" 结构清晰回答: 1. **引言**:简要解释方法它们的作用。 2. **关键区别**:对比start()run()的行为。 3. **示例**:提供一个简单的Java代码示例来演示区别。 4. **原理**:解释线程状态为什么start()会创建新线程。 5. **结论**:总结何时使用哪个。 6. **生成相关问题**:在回答末尾添加相关问题。 使用中文回答: - 整个回答需要用中文。 生成相关问题: - 我应该添加3-4个相关问题,类似于示例中的格式。 - 例如: 1. 如何在Java中创建线程的其他方式? 2. 线程状态有哪些? 3. 为什么直接调用run()不是推荐的做法? 4. Runnable接口Thread类的关系? 引用标识: - 在引用内容末尾添加[^1]、[^2]等。但用户提供的引用不是直接可用的源,所以我需要基于内容自然地添加引用。例如,如果我从引用[1]中借用观点,就加[^1]。 确保LaTeX正确: - 用户的问题没有涉及数学表达式,所以可能不需要使用LaTeX。但如果提到任何公式或代码,确保格式正确。 - 代码块应该像示例中一样使用```格式。 完整回答结构: - 先解释start()方法。 - 然后解释run()方法。 - 对比区别。 - 代码示例。 - 相关问题。 最终输出应包括: - 清晰的中文解释。 - 代码示例(如果需要)。 - 引用标识。 - 相关问题部分。 </think>### Thread.start() Thread.run() 的区别Java线程编程中,`Thread.start()` `Thread.run()` 是两个关键方法,它们的行为用途有本质区别。理解这些区别对于正确使用线程至关重要。下面我将逐步解释它们的区别、原理实际影响。 1. **方法作用行为区别** - **`Thread.start()`**: 此方法用于启动一个新线程。当你调用 `start()` 时,Java虚拟机(JVM)会创建一个新的执行线程,并使该线程进入就绪状态。随后,JVM会自动调用该线程的 `run()` 方法在新线程中执行代码。这个过程涉及线程调度生命周期管理,是异步操作。 - 例如:`t.start()` 会创建一个新线程并行运行代码[^1]。 - 线程状态变化:调用 `start()` 后,线程从新建状态(NEW)转移到就绪状态(RUNNABLE),最终由调度器分配到运行状态(RUNNING)[^4]。 - **`Thread.run()`**: 此方法只是一个普通的成员方法,不涉及线程创建。直接调用 `run()` 会在当前线程中同步执行代码,就像调用任何其他方法一样。它不会创建新线程,如果用于多线程场景,会导致代码串行运行,失去了多线程的并行优势。 - 例如:`t.run()` 只是执行 `run()` 方法的内容,不会启动新线程[^1]。 - 常见错误:许多初学者误以为调用 `run()` 能启动线程,但实际只是普通方法调用[^4]。 2. **关键区别总结** | 特性 | `Thread.start()` | `Thread.run()` | |-------------------|--------------------------------------------|------------------------------------------| | **线程创建** | 创建新线程并行执行代码 | 无新线程,代码在当前线程同步执行 | | **并发性** | 支持并发,提高程序效率 | 无并发效果,代码顺序执行 | | **适用场景** | 需要异步任务时(如后台计算或IO操作) | 仅用于测试或调试,不建议在生产代码中使用 | | **线程状态管理** | 触发线程生命周期变化(就绪→运行→终止) | 不影响线程状态,只是方法执行 | | **性能影响** | 涉及线程调度开销,但能充分利用多核CPU | 无额外开销,但无法利用多线程优势 | 简单来说,`start()` 是“点火器”,启动新线程;而 `run()` 是“引擎”,只包含要运行的代码逻辑[^1][^4]。 3. **代码示例演示** 下面通过一个Java示例直观展示区别: ```java public class ThreadDemo extends Thread { @Override public void run() { System.out.println("当前线程: " + Thread.currentThread().getName()); } public static void main(String[] args) { ThreadDemo t = new ThreadDemo(); // 调用 run():在当前线程(main)中执行 t.run(); // 输出: "当前线程: main" // 调用 start():在新线程中执行 t.start(); // 输出类似: "当前线程: Thread-0" } } ``` - **输出分析**: - `t.run()` 的输出线程名是 `main`,表示在主线程中运行。 - `t.start()` 的输出线程名是 `Thread-0`,表示在新创建的线程中运行。 这证明了 `start()` 创建新线程,而 `run()` 只是方法调用[^1]。 4. **原理底层机制** - **`start()` 的工作流程**: - 当调用 `start()` 时,JVM 会调用底层操作系统的线程创建API(如POSIX线程),创建一个新线程。 - 新线程被添加到线程池调度队列,由JVM调度器管理其执行。 - 线程启动后,自动调用 `run()` 方法执行任务。 - 如果多次调用 `start()` (线程已启动),会抛出 `IllegalThreadStateException`。 - **为什么 `run()` 不创建线程**: - `run()` 方法定义在 `Runnable` 接口中(Thread实现了该接口),只是一个任务定义方法。 - 直接调用 `run()` 不会触发JVM的线程管理逻辑,而是像普通方法一样由调用者线程执行。 - 通过 `Runnable` 接口,Java实现了线程逻辑与线程创建的分离,避免强制继承Thread类[^4]。 5. **最佳实践注意事项** - **何时使用 `start()`**: - 需要并行执行任务时(如并发下载、实时数据处理)。 - 在GUI应用中防止主线程阻塞。 - **何时避免 `run()`**: - 永远不要在多线程场景中直接调用 `run()`,因为它会导致程序失去并发性。 - 仅在调试时使用,例如测试 `run()` 方法逻辑是否正确。 - **常见错误**: - 误用 `run()` 导致“伪多线程”,即代码看似多线程但实际串行执行。 - 忘记调用 `start()` 而直接调用 `run()`,使线程无法启动。 总之,`Thread.start()` 是启动新线程的标准方式,启用并行执行;`Thread.run()` 只是执行代码块的方法,不涉及线程创建。正确使用 `start()` 能提升程序效率响应性[^1][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值