java创建线程池有哪几种方式? 为何搜索到的都是说4种

让我告诉你我当时掉进的陷阱。
所以我就开始研究Java多线程。
我见过其他人使用执行器来创建各种线程池,并认为这很简单。
结果呢?各种问题都找上门来。

比如有一年我搭建了一个电商系统,用newFixedThreadPool创建了一个固定大小的线程池,考虑到稳定性。
结果呢?后台任务过多,而且任务队列没有限制,直接爆了JVM堆。
那一刻我急得头晕目眩,只好重新开始。
后来发现这个东西是无限队列,任务多了就hold不住了。

还有新的CachedThreadPool,这个东西看起来很不错而且线程可以自动伸缩。
结果呢?有一次我正在处理一项作业。
结果开了1 00多个线程,直接烧毁了CPU。
查资料后发现,这个产品没有最大线程数限制,而且非常消耗资源。

最可怕的是newSingleThreadExecutor。
我以为单线程是最稳定的,但是我忘记检查队列设置。
这是一个无休无止的队列。
当后台任务太多时,JVM就会挂掉。
那一刻我有种想哭的感觉。

后来我意识到我必须自己构建一个线程池。
直接使用ThreadPoolExecutor,一切都可以自己决定。
例如ArrayBlockingQueue是有限的,如果任务太多就会被拒绝。
您还可以设置自己的拒绝策略。
当时我创建了一个订单处理系统,并使用ThreadPoolExecutor自己进行设置。
很稳定,没有再发生什么事情。

我也用过第三方工具,比如Hutool的ThreadUtil,真的很简单,几分钟就能搞定。
但如果你的场景很复杂,它的功能就不够了。
我曾经在开发一个报告生成工具,Hutool 运行得很好。
接下来我想添加拒绝策略,结果发现没有提供,所以我不得不自己修改源代码。

我还遇到了 ForkJoinPool。
在处理大数据时,使用分而治之算法直接使性能翻倍。
但那个场景很特殊,对于一般任务来说没有必要。
我还使用了Spring的ThreadPoolTask​​Executor。
他们的项目中常用,并且易于集成。
不过,如果不使用Spring的话,这个东西就是多余的了。

总结一下,表演者看似简单,实际上却有很多陷阱。
单独使用ThreadPoolExecutor问题有点多,但绝对稳定。
这取决于第三方工具的情况,所以不要太依赖它们。
特殊场景特殊处理。
这些都是我用真金白银克服的陷阱。
你不必犯我当年犯过的同样的错误。

java有几种实现线程的方式?

好了,我们就来说一下这三种创建线程的方式。

上周一位客户问我如何在 Java 中打开线程,我给了他这三个选项。

第一种方法是继承Thread类,自己写一个执行方法。
看这个例子,MyThread类扩展了Thread,所以在public void run()中写一些东西,比如Thread.sleep(1 000),让线程休眠1 秒。
这是最简单、最直接的,但是缺点是如果继承了Threads,以后想使用ExecutorService这样高级的东西就会很不方便。
此外,Java是单继承系统,只能继承一个类。
你的MyThread不能继承其他类。
使用时,MyThread t = new MyThread(),然后是t.start()。

其次,实现Runnable接口。
这是最常用的。
你看,Runnable 是一个接口。
它没有状态,只是 void run()。
您需要编写一个实现 Runnable 的 MyRunnable 类,然后重写 run() 方法。
这样做的好处是可以在一个类中同时实现多个接口,也可以从其他类继承。
耦合度低,可扩展性强。
使用时,Thread t = new Thread(new MyRunnable()),然后是t.start()。

第三种方式是实现Callable接口。
它与Runnable类似,但是Callable可以返回值并抛出异常。
如果你看一下 Callable,T 是返回值类型。
您需要编写一个实现 Callable 的 MyCallable 类,然后重写 call() 方法以返回整数。
该方法与Runnable类似,Future f = new Thread(new MyCallable()).start(),因此可以使用f.get()来获取返回值。
future非常重要,可以用来处理线程执行的结果。

你看,这三种方法各有其优点和缺点。
继承Thread虽然简单,但是耦合性很高。
Runnable的实现很灵活,但是编写起来需要更长的时间。
Callable 实现可以返回适合您需要处理结果的场景的值。

使用哪一种取决于您的需要。
如果你只是做一些简单的事情,不想操心那么多,你可以继承Thread。
如果追求高内聚低耦合或者想使用线程池,最好实现Runnable。
如果您需要从线程返回结果或处理异常,Callable 更适合。

无论如何,这取决于你。

java四种线程池创建

哎呀,说到Java线程池,这是一个常见的说法。
我们来谈谈执行工具类别中的静态方法。

第一个方法newFixedThreadPool是固定大小的线程。
就像工厂一样,工人的数量是固定的,不多也不少。
例如,如果你设置线程池中只有1 0个线程,那么无论你提交多少个任务,最多也只有1 0个线程在工作。
这个方法是在2 01 5 年提出的,当时很多大型网站都用它来控制并发线程数。
他们使用得越多,人们就越习惯它。

然后就是新增了一个SingleThread Executor,这个简单,只有一个线程,就像一个单独作战的士兵。
所有的工作都按顺序进行,一件接着一件,没有两件是同时完成的。
该方法是2 01 6 年引入的,主要是执行任务按顺序提交,并照顾任务的顺序。

我们来谈谈newCachedThreadPool。
这就像一个灵活的游侠。
当你进来时他会帮助你,当你出去时他会休息。
核心线程数为0,最大线程数为integer.MAX_VALUE,空闲时间超过6 0秒的线程将被回收。
这种方法出现于2 01 4 年,主要是根据运行任务的数量动态调整线程池的大小,特别适合短期的异步任务处理。

最后不得不提一下newScheduledThreadPool。
这是一个类似于世界上预定教学的任务。
他不仅无法定期进行工作,而且也无法在某个时间进行工作。
该方法于2 01 7 年被添加到Java并发包中,主要用于执行计划任务和周期性任务。

对于DelayedWorkQueue来说,它实际上并不是一个具体的池工作队列类型,而是一个接口。
就像学校的军训一样,把排队耽误要素的工作放到了去做。
这个接口已经存在于Java Concurrency包中,其类型实现是DelayQueue。
该队列中的元素就像军事计时器。
只有到了规定的时间,他们才能出去完成任务。

总的来说,这些沼泽和钢丝绳是世界上最强大的工具。
如果使用得当,它们可以帮助您解决许多并发编程问题。
但说实话,当时我没想到能了解这么多细节。
他是后来才明白这些的。