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

这是一道面试题。这两种方式有哪种区别?
Runnable将数据共享这一特点完美诠释。

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

public class Thread extends Object implements Runnable

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

9003228-b0ead469df42418c.png
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();
    }
}
9003228-8e55074aeee059fa.png
image.png
结果三个thread类都在卖各自的10张票,这是由于我们并没有给ticket设置为static变量,所以这个数据没有被录入元数据区,而被压入了局部变量表,在执行实例化操作后,各自生成了一块堆内存指向,此时并不存在数据共享这一概念。

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

9003228-e4dedbe8e21916fe.png
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();
    
    }
}
9003228-3bfd9e768d231c70.png
image.png
原理分析:这是由于三个不同的栈都指向了同一块堆内存对象,确保了他们操作的是同一个实例化对象。

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

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

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

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

关注公众号Code In Java,Java学习图谱,数据结构与算法资料等各种资料都可以在后台获取。等你哦~

猜你喜欢

转载自blog.csdn.net/weixin_33853794/article/details/87523554