【挑战并发】—– 实现多线程到底几种方式?我说两种!!!

前言

如果极限真的存在?那么它在哪里?好了,不装逼~。

JAVA并发相关知识体系,可谓是学了一遍又一遍,每次都嗯……这次再来一次系统学习。先来个开篇,实现多线程到底几种方式?这次我说是两种!!

官网说两种

先来看下Oracle官网文档描述(https://docs.oracle.com/javase/8/docs/api/index.html)

1618332534296

因为官网说实现多线程的方式就两种,那我也就说是两种

  • 方法一: 继承 Thread 类
  • 方法二: 实现 Runable 接口

民间还有好几种?

那么问题来了?网上好多文章说可以通过 Callable、FutureTask、线程池也可以实现多线程,这种说法对不对呢?

我只能说 说法不精确,那只能源码解读一波了,一个一个来,不急~

FutureTask、Callable

首先通过 FutureTask、Callable确实可以达到创建新的线程的效果。我们先看下FutureTask的类继承图

从类的继承图上来看,FutureTask也是实现了 Runable 接口,并且在构造函数里可以传入 Callable 类型参数。所以从本质上来讲,使用FutureTask实现多线程的方式也是通过Runable接口来实现的。

线程池的方式

看一下线程池的创建方法: ExecutorService executorService = Executors.newFixedThreadPool(1);

看一下newFixedThreadPool(1)方法

1
2
3
4
5
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

通过层层调用,其实生产线程的类是 DefaultThreadFactory 这个类,本质还是 调用new Thread()创建的线程。所以线程池实现多线程本质还是 通过 Thread 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;

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;
}
}

官网两种方法哪种方式比较好

实现Runable的方式比较好一点

  • 实现Runable接口新建线程损耗小一点。因为继承Thread类每次都要new一个线程以及后面去销毁损耗较大,但是实现了Runable接口可以重复利用一个线程去执行任务,并且线程池也是这么做的支持传入Runable接口作为参数。
  • JAVA不支持多继承,扩展性感觉差点
  • Thread类中也维护了一个Runable的属性,run()方法也是调用的Runable的方法。只是我们继承Thread类之后重写了run()方法。所以本质上还是使用Runable接口。

总结

  • 本质上实现多线程就只有两种方式,如果通过继承、包装来实现也算新的方式,那么JDK中那么多包装、继承Thread类、Runable接口的方式都能算实现多线程了。
  • 你知道的越多,你不知道的越多。

欢迎扫码关注

如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!

顶我一下下!
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2021 ListenerSun
  • 访问人数: | 浏览次数:

请我吃个棒棒糖可否~

支付宝
微信