别再说继承Thread类不适合共享资源了,这种方式和实现Runnable接口是一样的!

前言

最近再看多线程,关于多线程的实现方式上,我发现大多是帖子都是有些问题的。具体表现在证明继承Thread类和实现Runnable接口两种实现方式对资源共享的区别上。

先说结论(我认为这个是错误的)

大部分帖子都认为继承Thread类不适合资源共享,所以需要用实现Runnable接口的方式。一般都是用卖票的例子还说明,我随便找了一篇然后贴在这里:
别再说继承Thread类不适合共享资源了,这种方式和实现Runnable接口是一样的!_第1张图片
别再说继承Thread类不适合共享资源了,这种方式和实现Runnable接口是一样的!_第2张图片
然后贴出的运行结果无非是实现Runnable接口的三个线程共卖10张票,继承Thread类的线程则是每个线程卖10张,共卖30张票。这个代码真的能得出这个结论吗?

**当然不能!当然不能!当然不能!**最基本的控制变量法的条件都不满足,好多东西不一样,这种代码的验证方式一点也不严谨。不严谨的验证方式得出的结论也当然是不科学的。真不知道最原始的帖子是从哪来的,而且好多好多帖子都是这种结论。

接下来我们看看正确的验证方法

备注:本文不涉及线程安全,所以没有加同步锁,我也是特意截取的线程不安全的运行结果

方式一 继承Thread类

/**
继承Thread类
*/
public class MyThread extends Thread{
	//定义两个成员变量
    private int ticket=100;
    private String name;
    @Override
    public void run() {
        while(ticket > 0){
            System.out.println(ticket-- + "张票已被售卖,售卖窗口为" + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
    	//创建自定义类的实例
        MyThread myThread = new MyThread();
        //通过该实例创建三个线程
        Thread t1 = new Thread(myThread,"win1");
        Thread t2 = new Thread(myThread,"win2");
        Thread t3 = new Thread(myThread,"win3");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

结果如下:

别再说继承Thread类不适合共享资源了,这种方式和实现Runnable接口是一样的!_第3张图片
右下角可以看出,三个线程共同卖出了100张票!

方式二 实现Runnable接口

/**
实现Runnable接口
*/
public class MyInterface implements Runnable{
    private int ticket=100;//成员变量
    public void run() {
        while(ticket > 0){
            System.out.println(ticket-- + "张票已被售卖,售卖窗口为" + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
    	//创建实例
        MyInterface myInterface = new MyInterface();
        //以该实例为参数创建三个线程
        Thread t1 = new Thread(myInterface,"win1");
        Thread t2 = new Thread(myInterface,"win2");
        Thread t3 = new Thread(myInterface,"win3");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

结果:
别再说继承Thread类不适合共享资源了,这种方式和实现Runnable接口是一样的!_第4张图片
和继承Thread类一样,三个线程共同卖出了100张票!

方式三 模仿继承Thread类

方式一里MyThread类继承了Thread,而Thread实现了Runnable接口。为了模仿这种情况,我就用ImitateExtendThread类继承MyInterface,而MyInterface实现Runnable接口来模仿。

public class ImitateExtendThread extends MyInterface {
    private int ticket=100;
    private String name;
    @Override
    public void run() {
        while(ticket > 0){
            System.out.println(ticket-- + "张票已被售卖,售卖窗口为" + Thread.currentThread().getName());
        }
    }
    public static void main(String[] args) {
        ImitateExtendThread myImitateExtendThread = new ImitateExtendThread();
        Thread t1 = new Thread(myImitateExtendThread,"win1");
        Thread t2 = new Thread(myImitateExtendThread,"win2");
        Thread t3 = new Thread(myImitateExtendThread,"win3");
        t1.start();
        t2.start();
        t3.start();
    }
}

结果:
别再说继承Thread类不适合共享资源了,这种方式和实现Runnable接口是一样的!_第5张图片

综上

我的验证方式很简单,通过某个实例创建线程,然后启动线程,唯一的区别是实例不同(继承Thread类或者实现Runnable接口),然而不管是继承Thread类还是实现Runnable接口还是其他的,只要是通过同一个实例创建的线程都是可以实现资源共享的,也同样会发生线程安全的问题。

心得

我觉得那些错误的结论出现的原因在于,Runnable接口只提供了run()方法,而没有start()方法启动线程,导致代码实现不同,所以出现了不严谨的结论。希望以后自己学习要抱着对科学负责的态度,能够追求代码的本质,不要盲从。

你可能感兴趣的:(学习心得)