diff --git a/CHANGELOG.md b/CHANGELOG.md index d602e0dc0..5b9959bf7 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.19.M1 (2023-05-14) +# 5.8.19.M1 (2023-05-15) ### 🐣新特性 * 【db 】 优化HttpRequest.toString()内容打印(issue#3072@Github) @@ -11,6 +11,7 @@ * 【core 】 去除Opt头部的GPL协议头(pr#995@Gitee) * 【core 】 邮箱校验添加对中文的支持(pr#997@Gitee) * 【core 】 FileUtil.getMimeType增加webp识别(pr#997@Gitee) +* 【core 】 SyncFinisher增加setExceptionHandler方法(issue#I716SX@Gitee) ### 🐞Bug修复 * 【core 】 修复URLUtil.decode无法解码UTF-16问题(issue#3063@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/SyncFinisher.java b/hutool-core/src/main/java/cn/hutool/core/thread/SyncFinisher.java index a990fae2f..d131f1627 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/SyncFinisher.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/SyncFinisher.java @@ -41,6 +41,10 @@ public class SyncFinisher implements Closeable { * 结束同步器,用于等待所有worker线程同时结束 */ private CountDownLatch endLatch; + /** + * 异常处理 + */ + private Thread.UncaughtExceptionHandler exceptionHandler; /** * 构造 @@ -64,6 +68,18 @@ public class SyncFinisher implements Closeable { return this; } + /** + * 设置异常处理 + * + * @param exceptionHandler 异常处理器 + * @return this + * @since 5.8.19 + */ + public SyncFinisher setExceptionHandler(final Thread.UncaughtExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + return this; + } + /** * 增加定义的线程数同等数量的worker * @@ -127,10 +143,14 @@ public class SyncFinisher implements Closeable { endLatch = new CountDownLatch(workers.size()); if (null == this.executorService || this.executorService.isShutdown()) { - this.executorService = ThreadUtil.newExecutor(threadSize); + this.executorService = buildExecutor(); } for (Worker worker : workers) { - executorService.submit(worker); + if(null != this.exceptionHandler){ + executorService.execute(worker); + } else{ + executorService.submit(worker); + } } // 保证所有worker同时开始 this.beginLatch.countDown(); @@ -229,4 +249,16 @@ public class SyncFinisher implements Closeable { */ public abstract void work(); } + + /** + * 构建线程池,加入了自定义的异常处理 + * + * @return {@link ExecutorService} + */ + private ExecutorService buildExecutor() { + return ExecutorBuilder.create() + .setCorePoolSize(threadSize) + .setThreadFactory(new NamedThreadFactory("hutool-", null, false, exceptionHandler)) + .build(); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/thread/SyncFinisherTest.java b/hutool-core/src/test/java/cn/hutool/core/thread/SyncFinisherTest.java new file mode 100755 index 000000000..602048e7f --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/thread/SyncFinisherTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.core.thread; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Console; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class SyncFinisherTest { + /** + * https://gitee.com/dromara/hutool/issues/I716SX + * 设置ExceptionHandler捕获异常 + */ + @Test + public void executeExceptionTest() { + final AtomicBoolean hasException = new AtomicBoolean(false); + final SyncFinisher syncFinisher = new SyncFinisher(10); + syncFinisher.addWorker(()->{ + Console.log(Integer.parseInt("XYZ"));//这里会抛RuntimeException + }); + + syncFinisher.setExceptionHandler((t, e) -> { + hasException.set(true); + Assert.assertEquals("For input string: \"XYZ\"", e.getMessage()); + }); + + syncFinisher.start(); + IoUtil.close(syncFinisher); + ThreadUtil.sleep(300); + Assert.assertTrue(hasException.get()); + } + + /** + * https://gitee.com/dromara/hutool/issues/I716SX + * 默认情况下吞掉异常 + */ + @Test + public void executeExceptionTest2() { + final SyncFinisher syncFinisher = new SyncFinisher(10); + syncFinisher.addWorker(()->{ + Console.log(Integer.parseInt("XYZ"));//这里会忽略RuntimeException + }); + + syncFinisher.start(); + IoUtil.close(syncFinisher); + } +}