多线程两种实现方式的区别

本文探讨了Java中实现多线程的两种方式——继承Thread类和实现Runnable接口。虽然两者都能实现代码复用,但继承Thread支持单继承,而实现Runnable支持多实现。在数据共享方面,Runnable更好地体现了这一概念,因为多个线程可以访问同一资源。通过内存模型的解析,文章解释了为何Runnable在描述数据共享时更具优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象三个特征:封装、继承、多态。                                                                                                                                       首先注意接口与抽象之间的区别

实现与继承的区别

表面的区别就是单继承多实现

继承:如果多个类的某个部来分的功能相同,那么可以抽象出一个类出来,把他们的相同部分都放到父类里,让他们都继承这个类。

实现:如果多个类处理的目标是一源样的,但是处理的方法方式不同,那么就定义一个接口,也就是一个标准,让他们的实现这个接口,各自实现自己具体知的处理方法来处理那个目标

第一、联系

继承和接口都能实现代码重用,提高开发效率。提现了实物的传递性,继承关系达到复用的目的。

 

对于继承和实现的区别主要体现在继承式子类与父类百的继承,实现是接口的实现。
使用继承,可以减少代码量,常用方度法可以不必定义,而是直接继承父类定义好了的方法,提高编程效率问。体现了软件的三特性之一的可复用性。
使用接口,答只定义方法,没有具体的方法体,实现该接口的类可以对接口中回的方法灵活的根据实际情况定义,很好的是程序具有灵活、复用的特性答。

两者区别:

1、修饰不同

不同的修饰符修饰;实现:implements,继承:extends;

2、数量不同

Java只支持“接口”的多继承,不支持“类“”的多继承;而继承在java中具有单根性,子类只能继承一个父类。

总结为:单继承,多实现。

3、属性不同

在接口中只能定义全局常量(static final),和无实现的方法;而在继承中可以定义属性方法,变量,常量等。

4、调用不同

某个接口被类实现时,在类中一定要实现接口中的抽象方法;而继承想调用那个方法就调用那个方法。

总结:

接口是:对功能的描述(方法/行为),接口传达的意思是:拥有某种功能,能干嘛,比如:Serializable代表可序列化的。

继承是:什么是一种什么,继承传达的意思是:is-a,比如:猫 是一个 动物,猫就是动物的子类。

 


Runnable将数据共享这一特点完美诠释。

首先一定要明确的是,使用我们的Runnable接口与Thread类相比,解决了单继承的定义局限,所以在优先级上已经确定使用Runnable接口。
首先看jdk源码中Thread类定义:

 

public class Thread extends Object implements Runnable

发现Thread类实现了Runnable接口,那么这样一来就变为了以下形式。

image.png

我们可以看出,Runnable接口实现多线程其实很像代理模式的应用。很好的起到了设计模式中原则中的迪米特原则。之所以是"像",因为如果是代理设计模式,那么客户端调用的应该是接口里面提供的run()方法。

除了以上联系之外,使用Runnable接口可以比Thread类更好的描述出数据共享这一个概念,此时的数据共享指的是多个线程访问同一资源的操作。
范例:观察代码(每一个线程对象都必须通过start()启动)

 

package TestDemo;



class MyThread extends Thread{
    private int ticket=10;//这里的变量会压入局部变量表 因为并没有用static声明
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(this.ticket>0){
                System.out.println("sell,ticket="+this.ticket--);
            }
        }
    }
}

public class TestDemo{
    
    public static void main(String[] args) {
        MyThread thread1=new MyThread();
        MyThread thread2=new MyThread();
        MyThread thread3=new MyThread();

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

image.png

结果三个thread类都在卖各自的10张票,这是由于我们并没有给ticket设置为static变量,所以这个数据没有被录入元数据区,而被压入了局部变量表,在执行实例化操作后,各自生成了一块堆内存指向,此时并不存在数据共享这一概念。

在JVM内存模型基础上,我们可以看这张基于多线程的内存模型。

image.png

也很好的诠释了这一点。而Runnable就完美实现了这张内存模型图,我们可以把主存看作是MyThread类中的元数据,三个new Thread类匿名内部类对象实例看作3块工作内存。

范例:利用Runnable实现。

 

package TestDemo;



class MyThread implements Runnable{
    private int ticket=10;//这里的变量会压入局部变量表 因为并没有用static声明
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(this.ticket>0){
                System.out.println("sell,ticket="+this.ticket--);
            }
        }
    }
}

public class TestDemo{
    
    public static void main(String[] args) {
        MyThread mt=new MyThread();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    
    }
}

image.png

原理分析:这是由于三个不同的栈都指向了同一块堆内存对象,确保了他们操作的是同一个实例化对象。

因而当多个线程访问同一资源时候,我们使用Runnable更好的描述了数据共享这个概念(本质上是JVM虚拟栈是否指向同一块堆内存)

总结:请解释Thread类与Runnable接口实现多线程的区别(请解释多线程两种实现方式区别)?

Thread类是Runnable接口的子类,使用Runnable接口实现多线程可以避免单继承的局限性。
Runnable接口实现的多线程可以比Thread类实现的多线程更加清楚的描述数据共享的概念(本质上是JVM虚拟栈是否指向同一块堆内存)
可以将JVM内存布局以及基于多线程的内存模型画出来。

以及将两种多线程实现方式,白板编程出来。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值