thread继承Runnable吗_不能完全和完全不能的区别

thread继承Runnable吗_不能完全和完全不能的区别  在实际工作中,我们很可能习惯性地选择Runnable或Thread之一直接使用,根本没在意二者的区别,但在面试中很多自以为是的菜货面试官会经常而且非常严肃的问出:请你解释下Runnable或Thread的区别?尤其是新手就容易上当,不知如何回答,就胡乱编一通。鄙人今天告诉你们这二者本身就没有本质区别,就是接口和类的区别。问出这个问题的面试官本身就是个二流子!如果非要说区别,请看如下:Run…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

鄙人的新书《Elasticsearch权威指南》正式出版发行,欢迎购买!本书由华为、中兴高级技术专家全面审读并撰序,助您挑战百万年薪 购书链接:在这里插入图片描述

《Elasticsearch权威指南》

欢迎关注鄙人公众号,技术干货随时看!
在这里插入图片描述

  在实际工作中,我们很可能习惯性地选择Runnable或Thread之一直接使用,根本没在意二者的区别,但在面试中很多自以为是的菜货面试官会经常而且非常严肃的问出:请你解释下Runnable或Thread的区别?尤其是新手就容易上当,不知如何回答,就胡乱编一通。鄙人今天告诉你们这二者本身就没有本质区别,就是接口和类的区别。问出这个问题的面试官本身就是个二流子!如果非要说区别,请看如下:

  1. Runnable的实现方式是实现其接口即可
  2. Thread的实现方式是继承其类
  3. Runnable接口支持多继承,但基本上用不到
  4. Thread实现了Runnable接口并进行了扩展,而Thread和Runnable的实质是实现的关系,不是同类东西,所以Runnable或Thread本身没有可比性。

  网络上流传的最大的一个错误结论:Runnable更容易可以实现多个线程间的资源共享,而Thread不可以! 这是一个二笔的结论!网络得出此结论的例子如下:

//program--Thread
public class Test {
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        new MyThread().start();
        new MyThread().start();

    }


     static class MyThread extends Thread{
        private int ticket = 5;
        public void run(){
            while(true){
                System.out.println("Thread ticket = " + ticket--);
                if(ticket < 0){
                    break;
                }
            }
        }
    }
}

Jetbrains全家桶1年46,售后保障稳定

运行结果如下:

Thread ticket = 5
Thread ticket = 5
Thread ticket = 4
Thread ticket = 3
Thread ticket = 2
Thread ticket = 1
Thread ticket = 0
Thread ticket = 4
Thread ticket = 3
Thread ticket = 2
Thread ticket = 1
Thread ticket = 0

Process finished with exit code 0

  很显然,总共5张票但卖了10张。这就像两个售票员再卖同一张票,原因稍后分析。现在看看使用runnable的结果:

//program--Runnable
public class Test2 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MyThread2 mt=new MyThread2();
        new Thread(mt).start();
        new Thread(mt).start();


    }
    static class MyThread2 implements Runnable{
        private int ticket = 5;
        public void run(){
            while(true){
                System.out.println("Runnable ticket = " + ticket--);
                if(ticket < 0){
                    break;
                }
            }
        }
    }
}

  运行结果如下:


Runnable ticket = 5
Runnable ticket = 4
Runnable ticket = 3
Runnable ticket = 1
Runnable ticket = 0
Runnable ticket = 2

Process finished with exit code 0

  嗯,嗯,大多数人都会认为结果正确了,而且会非常郑重的得出:Runnable更容易可以实现多个线程间的资源共享,而Thread不可以! 真的是这样吗?大错特错!
  program–Thread这个例子结果多卖一倍票的原因根本不是因为Runnable和Thread的区别,看其中的如下两行代码:

        new MyThread().start();
        new MyThread().start();

  例子中,创建了两个MyThread对象,每个对象都有自己的ticket成员变量,当然会多卖1倍。如果把ticket定义为static类型,就离正确结果有近了一步(因为是多线程同时访问一个变量会有同步问题,加上锁才是最终正确的代码)。
现在看program–Runnable例子中,如下代码:

        MyThread2 mt=new MyThread2();
        new Thread(mt).start();
        new Thread(mt).start();        

  只创建了一个Runnable对象,肯定只卖一倍票(但也会有多线程同步问题,同样需要加锁),根本不是Runnable和Thread的区别造成的。再来看一个使用Thread方式的正确例子:

public class Test3  extends Thread {

        private int ticket = 10;

        public void run(){
            for(int i =0;i<10;i++){
                synchronized (this){
                    if(this.ticket>0){
                        try {
                            Thread.sleep(100);
                            System.out.println(Thread.currentThread().getName()+"卖票---->"+(this.ticket--));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

        public static void main(String[] arg){
            Test3 t1 = new Test3();
            new Thread(t1,"线程1").start();
            new Thread(t1,"线程2").start();
        }

}

运行结果如下:

线程1卖票---->10
线程1卖票---->9
线程1卖票---->8
线程1卖票---->7
线程1卖票---->6
线程1卖票---->5
线程1卖票---->4
线程1卖票---->3
线程1卖票---->2
线程1卖票---->1

Process finished with exit code 0

  上例中只创建了一个Thread对象(子类Test3),效果和Runnable一样。synchronized这个关键字是必须的,否则会出现同步问题,篇幅太长本文不做讨论。
  上面讨论下来,Thread和Runnable没有根本的没区别,只是写法不同罢了,事实是Thread和Runnable没有本质的区别,这才是正确的结论,和自以为是的大神所说的Runnable更容易实现资源共享,没有半点关系!
  现在看下Thread源码:

public
class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;
    private int            priority;
    private Thread         threadQ;
    private long           eetop;

  可以看出,Thread实现了Runnable接口,提供了更多的可用方法和成员而已。

  结论,Thread和Runnable的实质是继承关系,没有可比性。无论使用Runnable还是Thread,都会new Thread,然后执行run方法。用法上,如果有复杂的线程操作需求,那就选择继承Thread,如果只是简单的执行一个任务,那就实现runnable。
  再遇到二笔面试官问Thread和Runnable的区别,你可以直接鄙视了!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/198874.html原文链接:https://javaforall.net

(0)
上一篇 2025年8月24日 下午1:43
下一篇 2025年8月24日 下午2:15


相关推荐

  • TOF相机-非扫描三维成像

    TOF相机-非扫描三维成像飞行时间法(TOF)3D成像,是通过给目标连续发送光脉冲,然后用传感器接收从物体返回的光,通过探测光脉冲的飞行(往返)时间来得到目标物距离。这种技术跟3D激光传感器原理基本类似,只不过3D激光传感器是逐点扫描,而TOF相机则是同时得到整幅图像的深度信息;TOF相机与普通机器视觉成像过程也有类似之处,都是由光源、光学部件、传感器、控制电路以及处理电路等几部

    2022年5月26日
    47
  • 【数据仓库】【第十章】ODS层「建议收藏」

    【数据仓库】【第十章】ODS层「建议收藏」1.创建数据库现在数仓环境已经搭建好了;数据也都已经采集到hdfs上了;1)启动hive[atguigu@hadoop102hive]$bin/hive2)显示数据库hive(default)>showdatabases;3)创建数据库hive(default)>createdatabasegmall;4)使用数据库hive(default)>usegmall;ODS层1.用户行为数据(1)建表分析一行数据是什么:一条日志有哪些字段:

    2022年10月5日
    5
  • classpath环境变量配置

    classpath环境变量配置1 在了解 CLASSPATH 变量之前 我们要先设置 JAVA HOME 和 path 这两个环境变量 让 JAVA 环境可以成功地运行起来 然后 再开始我们的想法 因此 CLASSPATH 是在这两环境变量是已经配置好的基础上进行的配置 同理 JAVA HOME 也是在 path 基础上进行的配置 2 作用 配置过 CLASSPATH 环境后 java 命令是按照 CLASSPATH 变量中的路径来的寻找 class 文件的 不

    2026年3月19日
    2
  • RapidXml使用

    RapidXml使用vs2017rapidxml-1.131RapidXml使用1.1创建xml#include<iostream>#include”rapidxml/rapidxml.hpp”#include”rapidxml/rapidxml_utils.hpp”#include”rapidxml/rapidxml_print.hpp”usingnamespacerapidxml;voidcrateXml(){ xml_document<>doc; x

    2022年7月17日
    25
  • supersocket缓冲区_Super socket 记录知识

    supersocket缓冲区_Super socket 记录知识在 SocketServic 中运行你的 AppServerSup 提供了一个名叫 SocketServic 的项目 它是一个能够让 AppServer 运行于其中的容器 SocketServic 能够使你的 AppServer 以控制台或者 windows 服务的形式运行 需注册 有两种方法可以让你的 AppServer 运行于 SocketServic 之中 复制你的 AppServer 的 d

    2026年3月18日
    2
  • java数组初始化赋值_Java数组的三种初始化方式

    java数组初始化赋值_Java数组的三种初始化方式Java 语言中数组必须先初始化 然后才可以使用 所谓初始化就是为数组的数组元素分配内存空间 并为每个数组元素附初始值 注意 数组完成初始化后 内存空间中针对该数组的各个元素就有个一个默认值 基本数据类型的整数类型 byte short int long 默认值是 0 基本数据类型的浮点类型 float double 默认值是 0 0 基本数据类型的字符类型 char 默认值是 u0000 基本数据

    2026年3月26日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号