Java中“implements Runnable” 和“extends Thread” 的区别
fullstacker 发布于 2021-03-21
在可运行接口方法中,只创建一个类的实例,并且它已被不同的线程共享。因此,对于每个线程访问,counter的值都是递增的。

然而,在线程类方法中,必须为每个线程访问创建单独的实例。因此,为每个类实例分配不同的内存,每个类实例都有单独的计数器,值保持不变,这意味着不会发生增量,因为对象引用都不相同。

当您想从线程组访问相同的资源时,请使用Runnable接口。这里避免使用线程类,因为多个对象创建会消耗更多内存,并且会成为一个很大的性能开销。
实现Runnable的类不是线程,而是一个类。要使一个可运行的线程成为线程,您需要创建线程实例并将其作为目标传入。
在大多数情况下,如果只计划重写run()方法而不打算重写其他线程方法,则应该使用Runnable接口。这一点很重要,因为类不应该被子类化,除非程序员打算修改或增强类的基本行为。
当需要扩展超类时,实现可运行接口比使用线程类更合适。因为我们可以在实现Runnable接口时扩展另一个类来生成线程。

 class RunnableImpl implements Runnable {

    private int count = 0;

    public void run() {
        count ++;
        System.out.println("RunnableImpl : count : " + count);
    }
}


class ThreadExtends extends Thread {

    private int count = 0;

    public void run() {
        count++;
        System.out.println("ThreadExtends : count : " + count);
    }
}
    

public class ThreadRunnableDemo {

    public static void main(String args[]) throws Exception {
        // 多个线程共享相同的对象.
        RunnableImpl rc = new RunnableImpl();
        Thread t1 = new Thread(rc);
        t1.start();
        Thread.sleep(1000);
        Thread t2 = new Thread(rc);
        t2.start();
        Thread.sleep(1000); 
        Thread t3 = new Thread(rc);
        t3.start();

        // 为每个线程访问创建新对象
        ThreadExtends te1 = new ThreadExtends();
        te1.start();
        Thread.sleep(1000); 
        ThreadExtends te2 = new ThreadExtends();
        te2.start();
        Thread.sleep(1000);
        ThreadExtends te3 = new ThreadExtends();
        te3.start();
    }
}

输出

 RunnableImpl : count : 1
RunnableImpl : count : 2
RunnableImpl : count : 3
ThreadExtends : count : 1
ThreadExtends : count : 1
ThreadExtends : count : 1

备注:线程之间需要时间间隔,不然RunnableImpl的输出可能不会是1 2 3 顺序递增



全栈者
关注 私信
文章
31
关注
0
粉丝
0