JDK1.8 创建线程池有哪几种方式?

网友投稿 214 2022-09-01

JDK1.8 创建线程池有哪几种方式?

JDK1.8 创建线程池有哪几种方式?

newFixedThreadPool

定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程

测试代码:

public class TestThreadPool { //定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程 static ExecutorService fixedExecutor = Executors.newFixedThreadPool(3); public static void main(String[] args) { testFixedExecutor(); } //测试定长线程池,线程池的容量为3,提交6个任务,根据打印结果可以看出先执行前3个任务,3个任务结束后再执行后面的任务 private static void testFixedExecutor() { for (int i = 0; i < 6; i++) { final int index = i; fixedExecutor.execute(new Runnable() { public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); } }); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); fixedExecutor.shutdown(); } }

打印结果:

pool-1-thread-1 index:0pool-1-thread-2 index:1pool-1-thread-3 index:24秒后...pool-1-thread-3 index:5pool-1-thread-1 index:3pool-1-thread-2 index:4

newCachedThreadPool

可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制

测试代码:

public class TestThreadPool { //可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制 static ExecutorService cachedExecutor = Executors.newCachedThreadPool(); public static void main(String[] args) { testCachedExecutor(); } //测试可缓存线程池 private static void testCachedExecutor() { for (int i = 0; i < 6; i++) { final int index = i; cachedExecutor.execute(new Runnable() { public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); } }); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); cachedExecutor.shutdown(); } }

打印结果:

pool-1-thread-1 index:0pool-1-thread-6 index:5pool-1-thread-5 index:4pool-1-thread-4 index:3pool-1-thread-3 index:2pool-1-thread-2 index:14秒后...

newScheduledThreadPool 定长线程池,可执行周期性的任务

测试代码:

public class TestThreadPool { //定长线程池,可执行周期性的任务 static ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(3); public static void main(String[] args) { testScheduledExecutor(); } //测试定长、可周期执行的线程池 private static void testScheduledExecutor() { for (int i = 0; i < 3; i++) { final int index = i; //scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务 scheduledExecutor.scheduleWithFixedDelay(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName() + " index:" + index); } }, 0, 3, TimeUnit.SECONDS); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); scheduledExecutor.shutdown(); } }

打印结果:

pool-1-thread-1 index:0pool-1-thread-2 index:1pool-1-thread-3 index:2pool-1-thread-1 index:0pool-1-thread-3 index:1pool-1-thread-1 index:24秒后...

newSingleThreadExecutor

单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行

测试代码:

public class TestThreadPool { //单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行 static ExecutorService singleExecutor = Executors.newSingleThreadExecutor(); public static void main(String[] args) { testSingleExecutor(); } //测试单线程的线程池 private static void testSingleExecutor() { for (int i = 0; i < 3; i++) { final int index = i; singleExecutor.execute(new Runnable() { public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); } }); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); singleExecutor.shutdown(); } }

打印结果:

pool-1-thread-1 index:04秒后...pool-1-thread-1 index:1pool-1-thread-1 index:2

newSingleThreadScheduledExecutor

单线程可执行周期性任务的线程池

测试代码:

public class TestThreadPool { //单线程可执行周期性任务的线程池 static ScheduledExecutorService singleScheduledExecutor = Executors.newSingleThreadScheduledExecutor(); public static void main(String[] args) { testSingleScheduledExecutor(); } //测试单线程可周期执行的线程池 private static void testSingleScheduledExecutor() { for (int i = 0; i < 3; i++) { final int index = i; //scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务 singleScheduledExecutor.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName() + " index:" + index); } }, 0, 3, TimeUnit.SECONDS); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); singleScheduledExecutor.shutdown(); } }

打印结果:

pool-1-thread-1 index:0pool-1-thread-1 index:1pool-1-thread-1 index:2pool-1-thread-1 index:0pool-1-thread-1 index:1pool-1-thread-1 index:24秒后...

newWorkStealingPool

任务窃取线程池,不保证执行顺序,适合任务耗时差异较大。

线程池中有多个线程队列,有的线程队列中有大量的比较耗时的任务堆积,而有的线程队列却是空的,就存在有的线程处于饥饿状态,当一个线程处于饥饿状态时,它就会去其它的线程队列中窃取任务。解决饥饿导致的效率问题。

默认创建的并行 level 是 CPU 的核数。主线程结束,即使线程池有任务也会立即停止。

测试代码:

public class TestThreadPool { //任务窃取线程池 static ExecutorService workStealingExecutor = Executors.newWorkStealingPool(); public static void main(String[] args) { testWorkStealingExecutor(); } //测试任务窃取线程池 private static void testWorkStealingExecutor() { for (int i = 0; i < 10; i++) {//本机 CPU 8核,这里创建10个任务进行测试 final int index = i; workStealingExecutor.execute(new Runnable() { public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); } }); } try { Thread.sleep(4000);//这里主线程不休眠,不会有打印输出 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); // workStealingExecutor.shutdown(); } }

打印结果如下,index:8,index:9并未打印出:

ForkJoinPool-1-worker-1 index:0ForkJoinPool-1-worker-7 index:6ForkJoinPool-1-worker-5 index:4ForkJoinPool-1-worker-3 index:2ForkJoinPool-1-worker-4 index:3ForkJoinPool-1-worker-2 index:1ForkJoinPool-1-worker-0 index:7ForkJoinPool-1-worker-6 index:54秒后..

Executors创建线程池有哪几种方式?

Executors如何创建线程池?

Executors 类是从 JDK 1.5 开始就新增的线程池创建的静态工厂类,它就是创建线程池的,但是很多的大厂已经不建议使用该类去创建线程池。原因在于,该类创建的很多线程池的内部使用了无界任务队列,在并发量很大的情况下会导致 JVM 抛出 OutOfMemoryError,直接让 JVM 崩溃,影响严重。

但是 Executors 类究竟是如何使用的?

\1. newFixedThreadPool,创建定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程。

package constxiong.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试创建定长线程池 * @author ConstXiong */public class TestNewFixedThreadPool { public static void main(String[] args) { //创建工作线程数为 3 的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); //提交 6 个任务 for (int i = 0; i <6; i++) { final int index = i; fixedThreadPool.execute(() -> { try { //休眠 3 秒 Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); }); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); //关闭线程池后,已提交的任务仍然会执行完 fixedThreadPool.shutdown(); } }

打印结果:

pool-1-thread-2 index:1pool-1-thread-3 index:2pool-1-thread-1 index:04秒后...pool-1-thread-1 index:4pool-1-thread-3 index:5pool-1-thread-2 index:3

\2. newCachedThreadPool,创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制。

package constxiong.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试创建可缓存的线程池 * @author ConstXiong */public class TestNewCachedThreadPool { public static void main(String[] args) { //创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i <6; i++) { final int index = i; cachedThreadPool.execute(() -> { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); }); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); cachedThreadPool.shutdown(); } }

打印结果可以看出,创建的线程数与任务数相等

pool-1-thread-1 index:0pool-1-thread-3 index:2pool-1-thread-6 index:5pool-1-thread-4 index:3pool-1-thread-5 index:4pool-1-thread-2 index:14秒后...

\3. newScheduledThreadPool,创建定长线程池,可执行周期性的任务。

package constxiong.concurrency.a011;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/** * 测试创建定长线程池,可执行周期性的任务 * @author ConstXiong */public class TestNewScheduledThreadPool { public static void main(String[] args) { //创建定长线程池,可执行周期性的任务 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); for (int i = 0; i <3; i++) { final int index = i; //scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务 scheduledThreadPool.scheduleWithFixedDelay(() -> { System.out.println(Thread.currentThread().getName() + " index:" + index); }, 0, 3, TimeUnit.SECONDS); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); scheduledThreadPool.shutdown(); }}

打印结果:

pool-1-thread-1 index:0pool-1-thread-3 index:2pool-1-thread-2 index:1pool-1-thread-1 index:0pool-1-thread-2 index:1pool-1-thread-3 index:24秒后...

\4. newSingleThreadExecutor,创建单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行。

package constxiong.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试单线程的线程池 * @author ConstXiong */public class TestNewSingleThreadExecutor { public static void main(String[] args) { //单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行 ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); //提交 3 个任务 for (int i = 0; i <3; i++) { final int index = i; singleThreadPool.execute(() -> { //执行第二个任务时,报错,测试线程池会创建新的线程执行任务三 if (index == 1) { throw new RuntimeException("线程执行出现异常"); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); }); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); singleThreadPool.shutdown(); }}

打印结果可以看出,即使任务出现了异常,线程池还是会自动补充一个线程继续执行下面的任务

pool-1-thread-1 index:0Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 线程执行出现异常 at constxiong.concurrency.a011.TestNewSingleThreadExecutor.lambda$0(TestNewSingleThreadExecutor.java:21) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)4秒后...pool-1-thread-2 index:2

\5. newSingleThreadScheduledExecutor,创建单线程可执行周期性任务的线程池。

package constxiong.concurrency.a011;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/** * 测试单线程可执行周期性任务的线程池 * @author ConstXiong */public class TestNewSingleThreadScheduledExecutor { public static void main(String[] args) { //创建单线程可执行周期性任务的线程池 ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor(); //提交 3 个固定频率执行的任务 for (int i = 0; i <3; i++) { final int index = i; //scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务 singleScheduledThreadPool.scheduleAtFixedRate(() -> { System.out.println(Thread.currentThread().getName() + " index:" + index); }, 0, 3, TimeUnit.SECONDS); } try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("4秒后..."); singleScheduledThreadPool.shutdown(); } }

打印机结果可以看出 0-2 任务都被执行了 2 个周期

pool-1-thread-1 index:0pool-1-thread-1 index:1pool-1-thread-1 index:2pool-1-thread-1 index:0pool-1-thread-1 index:1pool-1-thread-1 index:24秒后...

\6. newWorkStealingPool,创建任务可窃取线程池,空闲线程可以窃取其他任务队列的任务,不保证执行顺序,适合任务耗时差异较大。

package constxiong.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试可任务窃取线程池 * @author ConstXiong */public class TestNewWorkStealingPool { public static void main(String[] args) { //创建 4个工作线程的 任务可窃取线程池,如果不设置并行数,默认取 CPU 总核数 ExecutorService workStealingThreadPool = Executors.newWorkStealingPool(4); for (int i = 0; i <10; i++) { final int index = i; workStealingThreadPool.execute(() -> { try { //模拟任务执行时间为 任务编号为0 1 2 的执行时间需要 3秒;其余任务200 毫秒,导致任务时间差异较大 if (index <= 2) { Thread.sleep(3000); } else { Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " index:" + index); }); } try { Thread.sleep(10000);//休眠 10 秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("10秒后..."); } }

打印结果可以看出,线程 ForkJoinPool-1-worker-0 把3-9的任务都执行完

ForkJoinPool-1-worker-0 index:3ForkJoinPool-1-worker-0 index:4ForkJoinPool-1-worker-0 index:5ForkJoinPool-1-worker-0 index:6ForkJoinPool-1-worker-0 index:7ForkJoinPool-1-worker-0 index:8ForkJoinPool-1-worker-0 index:9ForkJoinPool-1-worker-1 index:0ForkJoinPool-1-worker-3 index:2ForkJoinPool-1-worker-2 index:110秒后...

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot自动配置原理?
下一篇:mysql随机查询若干条数据的方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~