多线程的实现方法

2021-06-08 21:05

阅读:582

标签:end   任务   override   exti   并且   efi   多线程   创建   out   

一.创建线程的几种方式:

1.实现Runnable接口

 1 public class RunnableThread implements Runnable {
 2 
 3     @Override
 4 
 5     public void run() {
 6 
 7         System.out.println(‘用实现Runnable接口实现线程‘);
 8 
 9     }
10 
11 }

第 1 种方式是通过实现 Runnable 接口实现多线程,如代码所示,首先通过 RunnableThread 类实现 Runnable 接口,然后重写 run() 方法,之后只需要把这个实现了 run() 方法的实例传到 Thread 类中就可以实现多线程。

 

2.继承Thread类

public class ExtendsThread extends Thread {

    @Override

    public void run() {

        System.out.println(‘用Thread类实现线程‘);

    }

}

第 2 种方式是继承 Thread 类,如代码所示,与第 1 种方式不同的是它没有实现接口,而是继承 Thread 类,并重写了其中的 run() 方法。

 

3.线程池创建

static class DefaultThreadFactory implements ThreadFactory {

    DefaultThreadFactory() {

        SecurityManager s = System.getSecurityManager();

        group = (s != null) ? s.getThreadGroup() :

            Thread.currentThread().getThreadGroup();

        namePrefix = "pool-" +

            poolNumber.getAndIncrement() +

            "-thread-";

    }

    public Thread newThread(Runnable r) {

        Thread t = new Thread(group, r,

                    namePrefix + threadNumber.getAndIncrement(),

0);

        if (t.isDaemon())

            t.setDaemon(false);

        if (t.getPriority() != Thread.NORM_PRIORITY)

            t.setPriority(Thread.NORM_PRIORITY);

        return t;

    }

}

对于线程池而言,本质上是通过线程工厂创建线程的,默认采用 DefaultThreadFactory ,它会给线程池创建的线程设置一些默认值,比如:线程的名字、是否是守护线程,以及线程的优先级等。但是无论怎么设置这些属性,最终它还是通过 new Thread() 创建线程的 ,只不过这里的构造函数传入的参数要多一些,由此可以看出通过线程池创建线程并没有脱离最开始的那两种基本的创建方式,因为本质上还是通过 new Thread() 实现的。

4.通过实现Callable接口创建线程,有返回值

class CallableTask implements Callable {

    @Override

    public Integer call() throws Exception {

        return new Random().nextInt();

    }

}

//创建线程池

ExecutorService service = Executors.newFixedThreadPool(10);

//提交任务,并用 Future提交返回结果

Future future = service.submit(new CallableTask());

第 4 种线程创建方式是通过有返回值的 Callable 创建线程,Runnable 创建线程是无返回值的,而 Callable 和与之相关的 Future、FutureTask,它们可以把线程执行的结果作为返回值返回,如代码所示,实现了 Callable 接口,并且给它的泛型设置成 Integer,然后它会返回一个随机数。

但是,无论是 Callable 还是 FutureTask,它们首先和 Runnable 一样,都是一个任务,是需要被执行的,而不是说它们本身就是线程。它们可以放到线程池中执行,如代码所示, submit() 方法把任务放到线程池中,并由线程池创建线程,不管用什么方法,最终都是靠线程来执行的,而子线程的创建方式仍脱离不了最开始讲的两种基本方式,也就是实现 Runnable 接口和继承 Thread 类。

 

实现 Runnable 接口比继承 Thread 类实现线程要好

首先,我们从代码的架构考虑,实际上,Runnable 里只有一个 run() 方法,它定义了需要执行的内容,在这种情况下,实现了 Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,权责分明。

第二点就是在某些情况下可以提高性能,使用继承 Thread 类方式,每次执行一次任务,都需要新建一个独立的线程,执行完任务后线程走到生命周期的尽头被销毁,如果还想执行这个任务,就必须再新建一个继承了 Thread 类的类,如果此时执行的内容比较少,比如只是在 run() 方法里简单打印一行文字,那么它所带来的开销并不大,相比于整个线程从开始创建到执行完毕被销毁,这一系列的操作比 run() 方法打印文字本身带来的开销要大得多,相当于捡了芝麻丢了西瓜,得不偿失。如果我们使用实现 Runnable 接口的方式,就可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次新建销毁线程,大大降低了性能开销。

第三点好处在于 Java 语言不支持双继承,如果我们的类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,这样一来,如果未来这个类需要继承其他类实现一些功能上的拓展,它就没有办法做到了,相当于限制了代码未来的可拓展性。

综上所述,我们应该优先选择通过实现 Runnable 接口的方式来创建线程。

 

多线程的实现方法

标签:end   任务   override   exti   并且   efi   多线程   创建   out   

原文地址:https://www.cnblogs.com/britz/p/14511535.html


评论


亲,登录后才可以留言!