多线程:继承Thread和实现Runnable的区别

在给出这两个区别之前,我们先看看Thread类的源代码。

class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }    

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }    

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }    

    public synchronized void start() {
    }
}

一个Thread类实现了Runnable接口,Runnable接口里面只有一个方法run();

1、通过继承Thread类实现多线程

/**
 * 观察结果可以发现Thread-0 和 Thread-1输出的i
 * 不是连续的,因为程序每次创建线程对象都需要创建一
 * 个FirstThread对象
 * @author cjc
 *
 */
public class FirstThread extends Thread{
    private int i;
    public void run(){
        for(; i < 50 ; i++){
            System.out.println(this.getName() + " " + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for(int i = 0; i < 50; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
            if(i== 20){

                new FirstThread().start();  
                new FirstThread().start();
            }
        }
    }
}

输出结果:

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
main 20
main 21
main 22
main 23
main 24
Thread-0 0
Thread-1 0
Thread-0 1
main 25
Thread-0 2
Thread-1 1
Thread-0 3
main 26
Thread-0 4
Thread-1 2
Thread-0 5
main 27
Thread-0 6
Thread-1 3
Thread-0 7
main 28
Thread-0 8
Thread-1 4
Thread-0 9
main 29
Thread-0 10
Thread-1 5
Thread-0 11
main 30
Thread-0 12
Thread-1 6
Thread-0 13
main 31
Thread-0 14
Thread-1 7
Thread-0 15
main 32
Thread-0 16
Thread-1 8
Thread-0 17
main 33
Thread-0 18
Thread-1 9
Thread-0 19
main 34
Thread-0 20
Thread-1 10
Thread-0 21
main 35
Thread-0 22
Thread-1 11
Thread-0 23
main 36
Thread-0 24
Thread-1 12
Thread-0 25
main 37
Thread-0 26
Thread-1 13
Thread-0 27
main 38
Thread-0 28
Thread-1 14
Thread-0 29
main 39
Thread-0 30
Thread-1 15
Thread-0 31
main 40
Thread-0 32
Thread-1 16
Thread-0 33
main 41
Thread-0 34
Thread-1 17
Thread-0 35
main 42
Thread-0 36
Thread-1 18
Thread-0 37
main 43
Thread-0 38
Thread-1 19
Thread-0 39
main 44
Thread-0 40
Thread-1 20
Thread-0 41
main 45
Thread-0 42
Thread-1 21
Thread-0 43
main 46
Thread-0 44
Thread-1 22
Thread-0 45
main 47
Thread-0 46
Thread-1 23
Thread-0 47
main 48
Thread-0 48
Thread-1 24
Thread-0 49
main 49
Thread-1 25
Thread-1 26
Thread-1 27
Thread-1 28
Thread-1 29
Thread-1 30
Thread-1 31
Thread-1 32
Thread-1 33
Thread-1 34
Thread-1 35
Thread-1 36
Thread-1 37
Thread-1 38
Thread-1 39
Thread-1 40
Thread-1 41
Thread-1 42
Thread-1 43
Thread-1 44
Thread-1 45
Thread-1 46
Thread-1 47
Thread-1 48
Thread-1 49

由输出结果可以发现,共有三个线程:一个是main、一个是Thread-0、另一个就是Thread-1;由程序可以发现main线程输出的i是局部变量的i,只有main线程可以访问,而Thread-0和Thread-1所有的变量i却是类的实例变量,那为什么Thread-0和Thread-1输出的变量i为什么不是连续的呢?

这是因为FirstThread继承Thread,调用start()方法跑run()方法的时候,run()方法里面的target是线程对象本身,Thread-0和Thread-1是独立的,也就是Thread-0和Thread-1虽然是并行进行,但是他们访问的资源都是独立的。

2、通过实现Runnable接口实现多线程

public class SecondRun implements Runnable{

    private int i;
    @Override
    public void run() {
        for(; i < 50 ; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);    //由于不再是继承Thread,所以getName()方法不再是本对象的
        }       
    }
    public static void main(String[] args) {
        for(int i = 0; i < 50; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
            if(i== 20){
                SecondRun st = new SecondRun();
                new Thread(st, "新线程0").start();
                new Thread(st, "新线程1").start();
            }
        }
    }
}

输出结果:

main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
main 10
main 11
main 12
main 13
main 14
main 15
main 16
main 17
main 18
main 19
main 20
main 21
main 22
main 23
main 24
main 25
main 26
main 27
main 28
main 29
main 30
新线程1 0
新线程0 0
新线程1 1
main 31
新线程1 3
新线程0 2
新线程1 4
main 32
新线程1 6
新线程0 5
新线程1 7
main 33
新线程1 9
新线程0 8
新线程1 10
main 34
新线程1 12
新线程0 11
新线程1 13
新线程1 15
main 35
新线程1 16
新线程0 14
新线程1 17
main 36
新线程1 19
新线程0 18
新线程1 20
main 37
新线程1 22
新线程0 21
新线程0 24
新线程0 25
新线程0 26
新线程0 27
新线程0 28
新线程0 29
新线程0 30
新线程0 31
新线程0 32
新线程0 33
新线程0 34
新线程0 35
新线程0 36
新线程0 37
新线程0 38
新线程0 39
新线程0 40
新线程0 41
新线程0 42
新线程0 43
新线程0 44
新线程0 45
新线程0 46
新线程0 47
新线程1 23
main 38
新线程1 49
新线程0 48
main 39
main 40
main 41
main 42
main 43
main 44
main 45
main 46
main 47
main 48
main 49

我们可以看到main方法独立使用自己的局部变量i,而Thread-0和Thread-1的i是连续的。说明Thread-0和Thread-1共用一份资源
这个类是实现了Runable的run()方法,本身并不是Thread的子类,它与Thread类没有一点儿关系,我们看main方法里面的这三句代码:

                SecondRun st = new SecondRun();
                new Thread(st, "新线程0").start();
                new Thread(st, "新线程1").start();

也就是说,它只创建了一个Runnable对象,然后创建两个线程,把同一个Runnable对象传给线程,他们共用一个target,即他们共用一份资源。

总结:这两种方式使用的情景不同,如果是火车站售票,那肯定是用实现Runnable这种方式,因为他们共用一份票。现实开发中,用的更多的是实现Runnable接口。

=============
实现多线程,线程运行的代码块在run()方法里面,但是调用的时候不能直接调用run(),而是调用start()。如果直接调用run(),相当于调用run()这个普通方法,程序的输出只有main线程,并且执行都是一个循环完了接下去一个循环。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值