系统启动一个新线程的成本时比较高的,因为它涉及于操作系统交涉。在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存期限很短的线程时,更应该考虑使用线程池。
 与数据库连接池类似的是,线程池在启动时即创建大量空闲的线程,程序将一个Runnable对像或Callable对象传给线程池,线程池就会启动一个线程来执行他们的run()或call()方法,放run()或call()方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个Runnable对象的run()或call()方法。
 除此之外,使用线程池可以有效地控制系统中并发线程的数量,当系统中包含大量并发线程时,会导致系统性能急剧下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过此数。

1.Java8改进的线程池

 在Java5以前,开发者必须手动实现自己的线程池;从Java5开始,Java内建支持线程池。Java5新增了一个Executors工厂类来产生线程池,该工厂类包含了如下几个静态工厂方法来创建线程池。

  • newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中。
  • newFixedThreadPool(int nThreads):创建一个可重用的,具有固定线程数的线程池。
  • newSingleThreadExecutor():创建一个只有单线程的线程池,它相当于调用newFixedThreadPool()方法时传入参数为1。
  • newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务。corePoolSize指池中所保存的线程数,即使线程是空闲的也被保存在线程池内。
  • newSingleThreadScheduledExecutor():创建只有一个线程的线程池,它可以在指定延迟后执行线程任务。
  • ExecutorService newWorkStealingPool(int parallelism):创建持有足够的线程的线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争。
  • ExecutorService newWorkStealingPool():该方法是前一个方法的简化版本。如果当前机器有四个CPU,则目标并行级别被设置为4,也就是相当于前一个方法传入4作为参数。

 上面7个方法中前三个方法返回ExecutorService对象,该对象代表一个线程池,它可以执行Runnable对象或Callable对象所代表的线程;而中间两个方法返回一个ScheduledExecutorSerivce线程池,它是ExecutorService的子类,它可以在指定延迟后执行线程任务;最后两个方法则是Java8新增的,这两个方法可以充分利用多CPU并行能力。这两个方法生成的work stealing池,都相当于后台线程池,如果所有的前台线程都死亡了,work stealing 池中的线程会自动死亡。
 由于目前计算机硬件的发展日新月异,即使普通用户的电脑通常也都是多核CPU,因此Java8在线程支持上也增加了利用多CPU并行的能力,这样可以更好地发挥底层硬件的性能。

 ExecutorService代表尽快执行线程的线程池(只要线程池中有空闲线程,就立即执行线程任务),程序只要将一个Runnable对象或Callable对象(代表线程任务)提交给该线程池,该线程池会尽快执行该任务。ExecutorService里提供了如下三个方法。

  • Future<?> submit(Runnable task):将一个Runnable对象提交给指定的线程池,线程池将在有空闲线程时执行Runnable对象代表的任务。其中Future对象代表Runnable任务的返回值——但run()方法没有返回值,所以Future对象将在run()方法执行结束后返回null(),但可以调用Future的isDone(),isCancelled()方法来获得Runnable对象的执行状态。
  • Future submit(Runnable task,T result):将一个Runnable对象提交给指定的线程池,线程池将在有空闲线程时执行Runnable对象代表的任务,其中result显式指定线程执行结束后返回值,所以Future对象将在run()方法执行结束后返回result。
  • Future submit(Callable task):将一个Callable对象提交给指定的线程池,线程池将在有空闲线程时执行Callable对象代表的任务。其中Future代表Callable对象里call()方法的返回值。

 ScheduledExecutorService代表可在指定延迟后或周期性地执行线程任务的线程池,它提供如下4个方法。

  • ScheduledFuture schedule(Callable callable,long delay,TimeUnit unit):指定callable任务将在delay延迟后执行。
  • ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit):指定command任务将在delay延迟后执行。
  • ScheduledFuture scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit):指定command任务将在delay延迟后执行,而且以设定频率重复执行。也就是说在initialDelay 后开始执行,依次在 initialDelay+period,initialDelay+2*period···处重复执行,依此类推。
  • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit):创建并执行一个在给定初始延迟后首次启动的定期操作,随后在每一次执行终止和下一次执行开始之间都存在给定的延迟。如果任务在任一次执行时遇到异常,就会取消后续执行;否则通过程序来显式取消或终止该任务。、

 用完一个线程池后,应该调用该线程池的shutdown()方法,该方法将启动线程池的关闭序列,调用shutdown()方法后的线程池不再接受新任务,但会将以前所有已提交任务执行完成。当线程池中所有任务执行完成后,池中的所有线程都会死亡;另外也可以调用线程池的shutdownNow()方法来关闭线程池,改方法试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
使用线程池来执行线程任务的步骤如下:

  • 调用Executors类的静态工厂方法来创建一个ExecutorService对象,该对象代表一个线程池。
  • 创建Runnable实现类或Callable实现类的实例,作为线程执行任务。
  • 调用ExecutorService对象的submit()方法来提交Runnable实例或Callable实例。
  • 当不想提交任何任务时,调用ExecutorService对象的shutdown()方法来关闭线程池。

示例代码:

public class ThreadPoolTest {

   public static void main(String[] args) {

       //创建一个具有固定线程数的线程池
       ExecutorService executorService = Executors.newFixedThreadPool(6);

       Runnable target = () -> {
           for (int i = 0; i < 10; i++) {
               System.out.println("t_name:" + Thread.currentThread().getName() + ",i:" + i);
           }
       };

       //向线程池中提交两个线程
       executorService.submit(target);
       executorService.submit(target);
       //关闭线程池
       executorService.shutdown();
   }
}

运行结果:

t_name:pool-1-thread-1,i:0
t_name:pool-1-thread-1,i:1
t_name:pool-1-thread-1,i:2
t_name:pool-1-thread-1,i:3
t_name:pool-1-thread-1,i:4
t_name:pool-1-thread-2,i:0
t_name:pool-1-thread-1,i:5
t_name:pool-1-thread-1,i:6
t_name:pool-1-thread-2,i:1
t_name:pool-1-thread-1,i:7
t_name:pool-1-thread-1,i:8
t_name:pool-1-thread-2,i:2
t_name:pool-1-thread-1,i:9
t_name:pool-1-thread-2,i:3
t_name:pool-1-thread-2,i:4
t_name:pool-1-thread-2,i:5
t_name:pool-1-thread-2,i:6
t_name:pool-1-thread-2,i:7
t_name:pool-1-thread-2,i:8
t_name:pool-1-thread-2,i:9

注意:创建了Runnable实现类之后程序没有直接创建线程,启动线程来执行该Runnable任务,而是通过线程池来执行该任务。

2.Java8增强的ForkJoinPool

 为了充分利用CPU,多核CPU的性能优势,计算机软件系统可以充分“挖掘”每个CPU的计算能力,绝不能让某个CPU处于“空闲”状态。为了充分利用多CPU,多核CPU的优势,可以考虑把一个任务拆分成多个“小任务”,把多个“小任务”放在多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来即可。
 Java7提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结果。ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池。ForkJoinPool提供了如下两个常用的构造器。

  • ForkJoinPool(int parallelism):创建一个包含parallelism个并行线程的ForkJoinPool。
  • ForkJoinPool():以Runtime.availableProcessors()方法的返回值作为parallelism参数来创建ForkJoinPool。

 Java8进一步扩展了ForkJoinPool的功能,Java8为ForkJoinPool增加了通用池功能。ForkJoinPool类通过如下两个静态方法提供通用池功能。

  • ForkJoinPool commonPool():改方法返回一个通用池,通用池的运行状态不会受shutdown()或shutdownNow()方法的影响。当然,如果程序直接执行System.exit(0);来终止虚拟机,通用池以及通用池中正在执行的任务都将会被自动终止。
  • int getCommonPoolParallelism():该方法返回通用池的并行级别。

 创建了ForkJoinPool实例后,就可以调用ForkJoinPool的submit(ForkJoinTask task)或invoke(ForkJoinTask task)方法来执行指定任务了,其中ForkJoinTask代表一个可以并行,合并的任务。ForkJoinTask 是一个抽象类,它还有两个抽象子类:RecursiveAction和RecursiveTask。其中RecursiveTask代表有返回值的任务,而RecursiveAction代表没有返回值的任务。

下面以执行没有返回值的“大任务”(简单地打印0-300的数值)为例,程序将一个“大任务”拆分成多个“小任务”,并将任务交给ForkJoinPool来执行:

public class PrintTask extends RecursiveAction {

   //每个“小任务最多打印50个数”
   private static final int THRESHOLD = 50;

   private int start;

   private int end;

   public PrintTask(int start, int end) {
       this.start = start;
       this.end = end;
   }

   @Override
   protected void compute() {
       if (end - start < THRESHOLD) {
           for (int i = start; i < end; i++) {
               System.out.println(Thread.currentThread().getName() + "的i值:" + i);
           }
       } else {
           //当end与start之间的差值大于THRESHOLD,即要打印的数超过50个时
           //将大任务分解成两个“小任务”
           int middle = (start + end) / 2;
           PrintTask left = new PrintTask(start, middle);
           PrintTask right = new PrintTask(middle, end);
           //并行执行两个“小任务”
           left.fork();
           right.fork();
       }
   }
}
public class ForkJoinPoolTest {

   public static void main(String[] args) throws InterruptedException {

       ForkJoinPool pool = new ForkJoinPool();

       //提交可分解的PrintTask任务
       pool.submit(new PrintTask(1, 300));
       pool.awaitTermination(2, TimeUnit.SECONDS);
       //关闭线程池
       pool.shutdown();
   }
}

运行结果:

ForkJoinPool-1-worker-2的i值:112
ForkJoinPool-1-worker-2的i值:113
ForkJoinPool-1-worker-2的i值:114
ForkJoinPool-1-worker-4的i值:38
ForkJoinPool-1-worker-6的i值:150
ForkJoinPool-1-worker-1的i值:262
ForkJoinPool-1-worker-3的i值:187
ForkJoinPool-1-worker-1的i值:263
ForkJoinPool-1-worker-6的i值:151
ForkJoinPool-1-worker-6的i值:152
ForkJoinPool-1-worker-4的i值:39
ForkJoinPool-1-worker-2的i值:115
ForkJoinPool-1-worker-4的i值:40
ForkJoinPool-1-worker-6的i值:153
ForkJoinPool-1-worker-0的i值:1
ForkJoinPool-1-worker-5的i值:75
ForkJoinPool-1-worker-1的i值:264
ForkJoinPool-1-worker-7的i值:225
ForkJoinPool-1-worker-3的i值:188
ForkJoinPool-1-worker-7的i值:226
ForkJoinPool-1-worker-1的i值:265
ForkJoinPool-1-worker-5的i值:76
ForkJoinPool-1-worker-0的i值:2
ForkJoinPool-1-worker-0的i值:3
ForkJoinPool-1-worker-6的i值:154
ForkJoinPool-1-worker-4的i值:41
ForkJoinPool-1-worker-2的i值:116
ForkJoinPool-1-worker-2的i值:117
ForkJoinPool-1-worker-2的i值:118
ForkJoinPool-1-worker-2的i值:119
ForkJoinPool-1-worker-2的i值:120
ForkJoinPool-1-worker-2的i值:121
ForkJoinPool-1-worker-4的i值:42
ForkJoinPool-1-worker-6的i值:155
ForkJoinPool-1-worker-0的i值:4
ForkJoinPool-1-worker-0的i值:5
ForkJoinPool-1-worker-0的i值:6
ForkJoinPool-1-worker-5的i值:77
ForkJoinPool-1-worker-1的i值:266
ForkJoinPool-1-worker-7的i值:227
ForkJoinPool-1-worker-3的i值:189
ForkJoinPool-1-worker-3的i值:190
ForkJoinPool-1-worker-3的i值:191
ForkJoinPool-1-worker-7的i值:228
ForkJoinPool-1-worker-1的i值:267
ForkJoinPool-1-worker-5的i值:78
ForkJoinPool-1-worker-0的i值:7
ForkJoinPool-1-worker-0的i值:8
ForkJoinPool-1-worker-6的i值:156
ForkJoinPool-1-worker-4的i值:43
ForkJoinPool-1-worker-2的i值:122
ForkJoinPool-1-worker-4的i值:44
ForkJoinPool-1-worker-6的i值:157
ForkJoinPool-1-worker-0的i值:9
ForkJoinPool-1-worker-5的i值:79
ForkJoinPool-1-worker-1的i值:268
ForkJoinPool-1-worker-7的i值:229
ForkJoinPool-1-worker-3的i值:192
ForkJoinPool-1-worker-7的i值:230
ForkJoinPool-1-worker-1的i值:269
ForkJoinPool-1-worker-5的i值:80
ForkJoinPool-1-worker-1的i值:270
ForkJoinPool-1-worker-0的i值:10
ForkJoinPool-1-worker-6的i值:158
ForkJoinPool-1-worker-4的i值:45
ForkJoinPool-1-worker-4的i值:46
ForkJoinPool-1-worker-4的i值:47
ForkJoinPool-1-worker-2的i值:123
ForkJoinPool-1-worker-4的i值:48
ForkJoinPool-1-worker-6的i值:159
ForkJoinPool-1-worker-0的i值:11
ForkJoinPool-1-worker-1的i值:271
ForkJoinPool-1-worker-5的i值:81
ForkJoinPool-1-worker-7的i值:231
ForkJoinPool-1-worker-3的i值:193
ForkJoinPool-1-worker-7的i值:232
ForkJoinPool-1-worker-5的i值:82
ForkJoinPool-1-worker-1的i值:272
ForkJoinPool-1-worker-0的i值:12
ForkJoinPool-1-worker-6的i值:160
ForkJoinPool-1-worker-4的i值:49
ForkJoinPool-1-worker-2的i值:124
ForkJoinPool-1-worker-4的i值:50
ForkJoinPool-1-worker-6的i值:161
ForkJoinPool-1-worker-0的i值:13
ForkJoinPool-1-worker-1的i值:273
ForkJoinPool-1-worker-5的i值:83
ForkJoinPool-1-worker-7的i值:233
ForkJoinPool-1-worker-7的i值:234
ForkJoinPool-1-worker-7的i值:235
ForkJoinPool-1-worker-7的i值:236
ForkJoinPool-1-worker-7的i值:237
ForkJoinPool-1-worker-7的i值:238
ForkJoinPool-1-worker-7的i值:239
ForkJoinPool-1-worker-7的i值:240
ForkJoinPool-1-worker-7的i值:241
ForkJoinPool-1-worker-3的i值:194
ForkJoinPool-1-worker-7的i值:242
ForkJoinPool-1-worker-7的i值:243
ForkJoinPool-1-worker-7的i值:244
ForkJoinPool-1-worker-7的i值:245
ForkJoinPool-1-worker-7的i值:246
ForkJoinPool-1-worker-7的i值:247
ForkJoinPool-1-worker-5的i值:84
ForkJoinPool-1-worker-1的i值:274
ForkJoinPool-1-worker-0的i值:14
ForkJoinPool-1-worker-6的i值:162
ForkJoinPool-1-worker-4的i值:51
ForkJoinPool-1-worker-2的i值:125
ForkJoinPool-1-worker-2的i值:126
ForkJoinPool-1-worker-2的i值:127
ForkJoinPool-1-worker-2的i值:128
ForkJoinPool-1-worker-2的i值:129
ForkJoinPool-1-worker-4的i值:52
ForkJoinPool-1-worker-6的i值:163
ForkJoinPool-1-worker-6的i值:164
ForkJoinPool-1-worker-6的i值:165
ForkJoinPool-1-worker-6的i值:166
ForkJoinPool-1-worker-6的i值:167
ForkJoinPool-1-worker-6的i值:168
ForkJoinPool-1-worker-0的i值:15
ForkJoinPool-1-worker-1的i值:275
ForkJoinPool-1-worker-5的i值:85
ForkJoinPool-1-worker-7的i值:248
ForkJoinPool-1-worker-7的i值:249
ForkJoinPool-1-worker-7的i值:250
ForkJoinPool-1-worker-7的i值:251
ForkJoinPool-1-worker-7的i值:252
ForkJoinPool-1-worker-3的i值:195
ForkJoinPool-1-worker-7的i值:253
ForkJoinPool-1-worker-5的i值:86
ForkJoinPool-1-worker-1的i值:276
ForkJoinPool-1-worker-0的i值:16
ForkJoinPool-1-worker-6的i值:169
ForkJoinPool-1-worker-4的i值:53
ForkJoinPool-1-worker-2的i值:130
ForkJoinPool-1-worker-4的i值:54
ForkJoinPool-1-worker-6的i值:170
ForkJoinPool-1-worker-0的i值:17
ForkJoinPool-1-worker-1的i值:277
ForkJoinPool-1-worker-5的i值:87
ForkJoinPool-1-worker-7的i值:254
ForkJoinPool-1-worker-3的i值:196
ForkJoinPool-1-worker-7的i值:255
ForkJoinPool-1-worker-5的i值:88
ForkJoinPool-1-worker-1的i值:278
ForkJoinPool-1-worker-0的i值:18
ForkJoinPool-1-worker-6的i值:171
ForkJoinPool-1-worker-4的i值:55
ForkJoinPool-1-worker-2的i值:131
ForkJoinPool-1-worker-4的i值:56
ForkJoinPool-1-worker-6的i值:172
ForkJoinPool-1-worker-0的i值:19
ForkJoinPool-1-worker-1的i值:279
ForkJoinPool-1-worker-5的i值:89
ForkJoinPool-1-worker-7的i值:256
ForkJoinPool-1-worker-7的i值:257
ForkJoinPool-1-worker-7的i值:258
ForkJoinPool-1-worker-7的i值:259
ForkJoinPool-1-worker-7的i值:260
ForkJoinPool-1-worker-7的i值:261
ForkJoinPool-1-worker-3的i值:197
ForkJoinPool-1-worker-5的i值:90
ForkJoinPool-1-worker-1的i值:280
ForkJoinPool-1-worker-1的i值:281
ForkJoinPool-1-worker-0的i值:20
ForkJoinPool-1-worker-0的i值:21
ForkJoinPool-1-worker-0的i值:22
ForkJoinPool-1-worker-0的i值:23
ForkJoinPool-1-worker-0的i值:24
ForkJoinPool-1-worker-0的i值:25
ForkJoinPool-1-worker-0的i值:26
ForkJoinPool-1-worker-0的i值:27
ForkJoinPool-1-worker-0的i值:28
ForkJoinPool-1-worker-0的i值:29
ForkJoinPool-1-worker-0的i值:30
ForkJoinPool-1-worker-6的i值:173
ForkJoinPool-1-worker-4的i值:57
ForkJoinPool-1-worker-2的i值:132
ForkJoinPool-1-worker-2的i值:133
ForkJoinPool-1-worker-2的i值:134
ForkJoinPool-1-worker-2的i值:135
ForkJoinPool-1-worker-2的i值:136
ForkJoinPool-1-worker-2的i值:137
ForkJoinPool-1-worker-2的i值:138
ForkJoinPool-1-worker-2的i值:139
ForkJoinPool-1-worker-2的i值:140
ForkJoinPool-1-worker-4的i值:58
ForkJoinPool-1-worker-6的i值:174
ForkJoinPool-1-worker-0的i值:31
ForkJoinPool-1-worker-0的i值:32
ForkJoinPool-1-worker-0的i值:33
ForkJoinPool-1-worker-1的i值:282
ForkJoinPool-1-worker-1的i值:283
ForkJoinPool-1-worker-1的i值:284
ForkJoinPool-1-worker-1的i值:285
ForkJoinPool-1-worker-5的i值:91
ForkJoinPool-1-worker-3的i值:198
ForkJoinPool-1-worker-3的i值:199
ForkJoinPool-1-worker-3的i值:200
ForkJoinPool-1-worker-3的i值:201
ForkJoinPool-1-worker-3的i值:202
ForkJoinPool-1-worker-3的i值:203
ForkJoinPool-1-worker-3的i值:204
ForkJoinPool-1-worker-3的i值:205
ForkJoinPool-1-worker-3的i值:206
ForkJoinPool-1-worker-3的i值:207
ForkJoinPool-1-worker-3的i值:208
ForkJoinPool-1-worker-3的i值:209
ForkJoinPool-1-worker-3的i值:210
ForkJoinPool-1-worker-3的i值:211
ForkJoinPool-1-worker-5的i值:92
ForkJoinPool-1-worker-5的i值:93
ForkJoinPool-1-worker-1的i值:286
ForkJoinPool-1-worker-0的i值:34
ForkJoinPool-1-worker-6的i值:175
ForkJoinPool-1-worker-4的i值:59
ForkJoinPool-1-worker-2的i值:141
ForkJoinPool-1-worker-4的i值:60
ForkJoinPool-1-worker-6的i值:176
ForkJoinPool-1-worker-0的i值:35
ForkJoinPool-1-worker-1的i值:287
ForkJoinPool-1-worker-5的i值:94
ForkJoinPool-1-worker-5的i值:95
ForkJoinPool-1-worker-5的i值:96
ForkJoinPool-1-worker-5的i值:97
ForkJoinPool-1-worker-3的i值:212
ForkJoinPool-1-worker-5的i值:98
ForkJoinPool-1-worker-1的i值:288
ForkJoinPool-1-worker-1的i值:289
ForkJoinPool-1-worker-1的i值:290
ForkJoinPool-1-worker-1的i值:291
ForkJoinPool-1-worker-1的i值:292
ForkJoinPool-1-worker-1的i值:293
ForkJoinPool-1-worker-0的i值:36
ForkJoinPool-1-worker-6的i值:177
ForkJoinPool-1-worker-6的i值:178
ForkJoinPool-1-worker-6的i值:179
ForkJoinPool-1-worker-6的i值:180
ForkJoinPool-1-worker-6的i值:181
ForkJoinPool-1-worker-4的i值:61
ForkJoinPool-1-worker-2的i值:142
ForkJoinPool-1-worker-4的i值:62
ForkJoinPool-1-worker-6的i值:182
ForkJoinPool-1-worker-0的i值:37
ForkJoinPool-1-worker-1的i值:294
ForkJoinPool-1-worker-1的i值:295
ForkJoinPool-1-worker-1的i值:296
ForkJoinPool-1-worker-1的i值:297
ForkJoinPool-1-worker-1的i值:298
ForkJoinPool-1-worker-1的i值:299
ForkJoinPool-1-worker-5的i值:99
ForkJoinPool-1-worker-5的i值:100
ForkJoinPool-1-worker-5的i值:101
ForkJoinPool-1-worker-5的i值:102
ForkJoinPool-1-worker-5的i值:103
ForkJoinPool-1-worker-3的i值:213
ForkJoinPool-1-worker-3的i值:214
ForkJoinPool-1-worker-3的i值:215
ForkJoinPool-1-worker-3的i值:216
ForkJoinPool-1-worker-5的i值:104
ForkJoinPool-1-worker-6的i值:183
ForkJoinPool-1-worker-6的i值:184
ForkJoinPool-1-worker-6的i值:185
ForkJoinPool-1-worker-6的i值:186
ForkJoinPool-1-worker-4的i值:63
ForkJoinPool-1-worker-2的i值:143
ForkJoinPool-1-worker-2的i值:144
ForkJoinPool-1-worker-4的i值:64
ForkJoinPool-1-worker-5的i值:105
ForkJoinPool-1-worker-5的i值:106
ForkJoinPool-1-worker-5的i值:107
ForkJoinPool-1-worker-5的i值:108
ForkJoinPool-1-worker-3的i值:217
ForkJoinPool-1-worker-5的i值:109
ForkJoinPool-1-worker-5的i值:110
ForkJoinPool-1-worker-5的i值:111
ForkJoinPool-1-worker-4的i值:65
ForkJoinPool-1-worker-2的i值:145
ForkJoinPool-1-worker-2的i值:146
ForkJoinPool-1-worker-2的i值:147
ForkJoinPool-1-worker-2的i值:148
ForkJoinPool-1-worker-2的i值:149
ForkJoinPool-1-worker-4的i值:66
ForkJoinPool-1-worker-4的i值:67
ForkJoinPool-1-worker-3的i值:218
ForkJoinPool-1-worker-4的i值:68
ForkJoinPool-1-worker-3的i值:219
ForkJoinPool-1-worker-4的i值:69
ForkJoinPool-1-worker-3的i值:220
ForkJoinPool-1-worker-4的i值:70
ForkJoinPool-1-worker-3的i值:221
ForkJoinPool-1-worker-3的i值:222
ForkJoinPool-1-worker-3的i值:223
ForkJoinPool-1-worker-4的i值:71
ForkJoinPool-1-worker-3的i值:224
ForkJoinPool-1-worker-4的i值:72
ForkJoinPool-1-worker-4的i值:73
ForkJoinPool-1-worker-4的i值:74

 如果大任务时有返回值的任务,则可以让任务继承RecursiveTask<T>,其中泛型参数T就代表了改任务的返回值类型。代码示例省略。

文章内容均取自《疯狂Java讲义-李刚》一书中多线程章节。截取重要知识点作为笔记记录,方便自己回顾。

posted on 2020-05-04 15:12  whn051799  阅读(113)  评论(0编辑  收藏  举报