From de692848bb04c5c881699216f80295318e3dfbac Mon Sep 17 00:00:00 2001 From: duandazhi Date: Wed, 3 Aug 2022 22:37:31 +0800 Subject: [PATCH 1/6] =?UTF-8?q?BlockPolicy=E5=A2=9E=E5=8A=A0@link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/thread/BlockPolicy.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/BlockPolicy.java b/hutool-core/src/main/java/cn/hutool/core/thread/BlockPolicy.java index 3fac35e1d..724b9daa8 100755 --- a/hutool-core/src/main/java/cn/hutool/core/thread/BlockPolicy.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/BlockPolicy.java @@ -10,6 +10,8 @@ import java.util.function.Consumer; * 如果阻塞过程中被中断,就会抛出{@link InterruptedException}异常
* 有时候在线程池内访问第三方接口,只希望固定并发数去访问,并且不希望丢弃任务时使用此策略,队列满的时候会处于阻塞状态(例如刷库的场景) * + * 其他系统内置的拒绝策略,见hutool定义的枚举 {@link RejectPolicy} 线程拒绝策略枚举. + * * @author luozongle * @since 5.8.0 */ From 570295d2bc638941d88cc68ad36836aaa333558e Mon Sep 17 00:00:00 2001 From: duandazhi Date: Wed, 3 Aug 2022 22:39:30 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9ACALLER=5FRUNS=20?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E4=B8=8D=E5=87=86=E7=A1=AE=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/thread/RejectPolicy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/RejectPolicy.java b/hutool-core/src/main/java/cn/hutool/core/thread/RejectPolicy.java index 0fdb8f2ce..65806b8ce 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/RejectPolicy.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/RejectPolicy.java @@ -20,7 +20,7 @@ public enum RejectPolicy { DISCARD(new ThreadPoolExecutor.DiscardPolicy()), /** 如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程) */ DISCARD_OLDEST(new ThreadPoolExecutor.DiscardOldestPolicy()), - /** 由主线程来直接执行 */ + /** 调用者线程来执行被丢弃的任务;一般可能是由主线程来直接执行 */ CALLER_RUNS(new ThreadPoolExecutor.CallerRunsPolicy()), /** 当任务队列过长时处于阻塞状态,直到添加到队列中,固定并发数去访问,并且不希望丢弃任务时使用此策略 */ BLOCK(new BlockPolicy()); From 24517f1403ba7166dc8f43e70c4cf6616c59d8ae Mon Sep 17 00:00:00 2001 From: duandazhi Date: Wed, 3 Aug 2022 23:09:30 +0800 Subject: [PATCH 3/6] CountDownLatch add example demo --- .../cn/hutool/core/thread/ThreadUtil.java | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java index 4e9621a11..7a0d44e6f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java @@ -4,6 +4,8 @@ import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Phaser; +import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -272,11 +274,45 @@ public class ThreadUtil { /** * 新建一个CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 * - * @param threadCount 线程数量 + * 示例:等6个同学都离开教室,班长才能锁门。 + *
{@code
+	 * CountDownLatch latch = new CountDownLatch(6); // 总共任务是6
+	 *  for (int x = 0; x < 6; x++) {
+	 *   //具体生产任务,可以用线程池替换
+	 *     new Thread(()->{
+	 *         try {
+	 *           //每个同学在角色待上5秒钟
+	 *             TimeUnit.SECONDS.sleep(5);
+	 *         } catch (InterruptedException e) {
+	 *             e.printStackTrace();
+	 *         }
+	 *         System.out.printf("【%s】同学,已经离开了教室%n", Thread.currentThread().getName());
+	 *         latch.countDown(); // 减1(每离开一个同学,减去1)
+	 *     },"同学 - " + x).start();
+	 * }
+	 * latch.await(); // 等待计数为0后再解除阻塞;(等待所有同学离开)
+	 * System.out.println("【主线程】所有同学都离开了教室,开始锁教室大门了。");
+	 * }
+	 * 
+ * + * @param taskCount 任务数量 * @return CountDownLatch */ - public static CountDownLatch newCountDownLatch(final int threadCount) { - return new CountDownLatch(threadCount); + public static CountDownLatch newCountDownLatch(final int taskCount) { + return new CountDownLatch(taskCount); + } + + /** + * 新建一个Phaser,一个同步辅助类,jdk1.7提供,可以完全替代CountDownLatch; + * + * Pharser: 移相器、相位器,可重用同步屏障; + * 功能可以替换:{@link CyclicBarrier}(固定线程)循环栅栏、{@link CountDownLatch}(固定计数)倒数计数、加上分层功能 + * + * @param taskCount 任务数量 + * @return Phaser + */ + public static Phaser newPhaser(final int taskCount) { + return new Phaser(taskCount); } /** From e0d3f2e4c549e289a250704d628ceb7a8d30b4af Mon Sep 17 00:00:00 2001 From: duandazhi Date: Wed, 3 Aug 2022 23:24:06 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=EF=BC=9AnewPhaser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/thread/ThreadUtil.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java index 7a0d44e6f..a4e651d9e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java @@ -287,7 +287,7 @@ public class ThreadUtil { * e.printStackTrace(); * } * System.out.printf("【%s】同学,已经离开了教室%n", Thread.currentThread().getName()); - * latch.countDown(); // 减1(每离开一个同学,减去1) + * latch.countDown(); // 减1(每离开一个同学,减去1),必须执行,可以放到 try...finally中 * },"同学 - " + x).start(); * } * latch.await(); // 等待计数为0后再解除阻塞;(等待所有同学离开) @@ -304,10 +304,37 @@ public class ThreadUtil { /** * 新建一个Phaser,一个同步辅助类,jdk1.7提供,可以完全替代CountDownLatch; + * @since 6.0.1 + * @author dazer * * Pharser: 移相器、相位器,可重用同步屏障; * 功能可以替换:{@link CyclicBarrier}(固定线程)循环栅栏、{@link CountDownLatch}(固定计数)倒数计数、加上分层功能 * + * 示例1:等6个同学都离开教室,班长才能锁门。 + *
{@code
+	 * Phaser phaser = new Phaser(6); // 总共任务是6
+	 *  for (int x = 0; x < 6; x++) {
+	 *   //具体生产任务,可以用线程池替换
+	 *     new Thread(()->{
+	 *         try {
+	 *           //每个同学在角色待上5秒钟
+	 *             TimeUnit.SECONDS.sleep(5);
+	 *         } catch (InterruptedException e) {
+	 *             e.printStackTrace();
+	 *         }
+	 *         System.out.printf("【%s】同学,已经离开了教室%n", Thread.currentThread().getN
+	 *         phaser.arrive(); // 减1 等价于countDown()方法(每离开一个同学,减去1),必须执行,可以放到 try...finally中
+	 *     },"同学 - " + x).start();
+	 * }
+	 * phaser.awaitAdvance(phaser.getPhase()); // 等价于latch.await()方法 等待计数为0后再解除阻塞;(等待所有同学离开)
+	 * System.out.println("【主线程】所有同学都离开了教室,开始锁教室大门了。");
+	 * }
+	 * 
+ * + * 示例2:7个同学,集齐7个龙珠,7个同学一起召唤神龙; + * 只需要:phaser.arrive(); --> phaser.arriveAndAwaitAdvance() //等待其他的线程就位 + * 该示例,也可以用:{@link CyclicBarrier} 进行实现 + * * @param taskCount 任务数量 * @return Phaser */ From e3c6e4e2c7ca82906c06422d9e376f8eb7a8fd2a Mon Sep 17 00:00:00 2001 From: duandazhi Date: Thu, 4 Aug 2022 10:21:26 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix=E9=94=99=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/hutool/core/thread/ThreadUtil.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java index a4e651d9e..45bdc0967 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java @@ -281,12 +281,13 @@ public class ThreadUtil { * //具体生产任务,可以用线程池替换 * new Thread(()->{ * try { - * //每个同学在角色待上5秒钟 - * TimeUnit.SECONDS.sleep(5); + * //每个同学在教室待上几秒秒钟 + * int time = ThreadLocalRandom.current().nextInt(1, 5); + * TimeUnit.SECONDS.sleep(time); * } catch (InterruptedException e) { * e.printStackTrace(); * } - * System.out.printf("【%s】同学,已经离开了教室%n", Thread.currentThread().getName()); + * System.out.printf("同学【%s】,已经离开了教室%n", Thread.currentThread().getName()); * latch.countDown(); // 减1(每离开一个同学,减去1),必须执行,可以放到 try...finally中 * },"同学 - " + x).start(); * } @@ -317,12 +318,13 @@ public class ThreadUtil { * //具体生产任务,可以用线程池替换 * new Thread(()->{ * try { - * //每个同学在角色待上5秒钟 + * //每个同学在教室待上几秒秒钟 + * int time = ThreadLocalRandom.current().nextInt(1, 5); * TimeUnit.SECONDS.sleep(5); * } catch (InterruptedException e) { * e.printStackTrace(); * } - * System.out.printf("【%s】同学,已经离开了教室%n", Thread.currentThread().getN + * System.out.printf("同学【%s】,已经离开了教室%n", Thread.currentThread().getName()); * phaser.arrive(); // 减1 等价于countDown()方法(每离开一个同学,减去1),必须执行,可以放到 try...finally中 * },"同学 - " + x).start(); * } From b9f2a914575b2bdd8c6e91978acf9798f62109b6 Mon Sep 17 00:00:00 2001 From: duandazhi Date: Thu, 4 Aug 2022 16:29:48 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9Anew=20CyclicBarr?= =?UTF-8?q?ier()=20=E5=BE=AA=E7=8E=AF=E6=A0=85=E6=A0=8F=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E8=BE=85=E5=8A=A9=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/thread/ThreadUtil.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java index 45bdc0967..c244ff5b6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java @@ -296,6 +296,8 @@ public class ThreadUtil { * } * * + * 该示例,也可以用:{@link Phaser} 移相器 进行实现 + * * @param taskCount 任务数量 * @return CountDownLatch */ @@ -303,6 +305,46 @@ public class ThreadUtil { return new CountDownLatch(taskCount); } + /** + * 新建一个CycleBarrier 循环栅栏,一个同步辅助类 + * + * 示例:7个同学,集齐7个龙珠,7个同学一起召唤神龙;前后集齐了2次 + *
{@code
+	 *         AtomicInteger times = new AtomicInteger();
+	 *         CyclicBarrier barrier = new CyclicBarrier(7, ()->{
+	 *             System.out.println("");
+	 *             System.out.println("");
+	 *             System.out.println("【循环栅栏业务处理】7个子线程 都收集了一颗龙珠,七颗龙珠已经收集齐全,开始召唤神龙。" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+	 *             times.getAndIncrement();
+	 *         }); // 现在设置的栅栏的数量为2
+	 *         for (int x = 0; x < 7; x++) {   // 创建7个线程, 当然也可以使用线程池替换。
+	 *             new Thread(() -> {
+	 *                 while (times.get() < 2) {
+	 *                     try {
+	 *                         System.out.printf("【Barrier - 收集龙珠】当前的线程名称:%s%n", Thread.currentThread().getName());
+	 *                         int time = ThreadLocalRandom.current().nextInt(1, 10); // 等待一段时间,模拟线程的执行时间
+	 *                         TimeUnit.SECONDS.sleep(time); // 模拟业务延迟,收集龙珠的时间
+	 *                         barrier.await(); // 等待,凑够了7个等待的线程
+	 *                         System.err.printf("〖Barrier - 举起龙珠召唤神龙〗当前的线程名称:%s\t%s%n", Thread.currentThread().getName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+	 *                         if (barrier.getParties() >= 7) {
+	 *                             barrier.reset(); // 重置栅栏,等待下一次的召唤。
+	 *                         }
+	 *                     } catch (Exception e) {
+	 *                         e.printStackTrace();
+	 *                     }
+	 *                 }
+	 *             }, "线程 - " + x).start();
+	 *         }
+	 * }
+ * + * 该示例,也可以用:{@link Phaser} 移相器 进行实现 + * @param taskCount 任务数量 + * @return 循环栅栏 + */ + public static CyclicBarrier newCyclicBarrier(final int taskCount) { + return new CyclicBarrier(taskCount); + } + /** * 新建一个Phaser,一个同步辅助类,jdk1.7提供,可以完全替代CountDownLatch; * @since 6.0.1