Advertisement

多任务共用一个大的线程池还是每个任务单独使用线程池?

阅读量:

1. 大线程池与多线程池

开发过程中的任务大致分为两大类:

  • IO密集型的任务具有显著的特性,在执行过程中通常需要短暂中断当前的任务去执行其他类型的I/O操作。
    • 计算密集型的任务其主要特点在于大部分运算和数据处理都在内存内部完成。

通过模拟两种不同的情况来考察结果如何变化

复制代码
 package org.example.objectsize;

    
  
    
 import java.io.File;
    
 import java.io.IOException;
    
 import java.nio.charset.StandardCharsets;
    
 import java.util.concurrent.CountDownLatch;
    
 import java.util.concurrent.ExecutorService;
    
 import java.util.concurrent.Executors;
    
 import java.util.concurrent.atomic.AtomicInteger;
    
 import org.apache.commons.io.FileUtils;
    
  
    
 public class IOTest {
    
  
    
     public static void main(String[] args) throws Exception{
    
     extracted();
    
     main1(args);
    
     }
    
  
    
     private static void extracted() throws InterruptedException {
    
     final AtomicInteger integer = new AtomicInteger();
    
     final  File file = new File("C:\ Users\ mxsm\ Desktop\ RocketMQ5\ aaa.txt");
    
     ExecutorService executorService = Executors.newFixedThreadPool(50);
    
     CountDownLatch latch =  new CountDownLatch(50);
    
     long l = System.currentTimeMillis();
    
     for(int i = 0; i < 50; ++i){
    
         executorService.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     try {
    
                         FileUtils.write(file, integer.get()+"", StandardCharsets.UTF_8);
    
                     } catch (IOException e) {
    
                         e.printStackTrace();
    
                     }
    
                 }while (integer.getAndIncrement() < 100000);
    
                 latch.countDown();
    
             }
    
         });
    
     }
    
     latch.await();
    
     System.out.println("大线程池:"+(System.currentTimeMillis()-l));
    
     executorService.shutdown();
    
     }
    
     public static void main1(String[] args) throws Exception{
    
     final AtomicInteger integer = new AtomicInteger();
    
     final  File file = new File("C:\ Users\ mxsm\ Desktop\ RocketMQ5\ aaa.txt");
    
     ExecutorService executorService1 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService2 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService3 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService4 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService5 = Executors.newFixedThreadPool(10);
    
     CountDownLatch latch =  new CountDownLatch(50);
    
     long l = System.currentTimeMillis();
    
     for(int i = 0; i < 10; ++i){
    
         executorService1.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     try {
    
                         FileUtils.write(file, integer.get()+"", StandardCharsets.UTF_8);
    
                     } catch (IOException e) {
    
                         e.printStackTrace();
    
                     }
    
                 }while (integer.getAndIncrement() < 100000);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService2.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     try {
    
                         FileUtils.write(file, integer.get()+"", StandardCharsets.UTF_8);
    
                     } catch (IOException e) {
    
                         e.printStackTrace();
    
                     }
    
                 }while (integer.getAndIncrement() < 100000);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService3.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     try {
    
                         FileUtils.write(file, integer.get()+"", StandardCharsets.UTF_8);
    
                     } catch (IOException e) {
    
                         e.printStackTrace();
    
                     }
    
                 }while (integer.getAndIncrement() < 100000);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService4.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     try {
    
                         FileUtils.write(file, integer.get()+"", StandardCharsets.UTF_8);
    
                     } catch (IOException e) {
    
                         e.printStackTrace();
    
                     }
    
                 }while (integer.getAndIncrement() < 100000);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService5.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     try {
    
                         FileUtils.write(file, integer.get()+"", StandardCharsets.UTF_8);
    
                     } catch (IOException e) {
    
                         e.printStackTrace();
    
                     }
    
                 }while (integer.getAndIncrement() < 100000);
    
                 latch.countDown();
    
             }
    
         });
    
     }
    
     latch.await();
    
     System.out.println("多线程池:"+(System.currentTimeMillis()-l));
    
     executorService1.shutdown();
    
     executorService2.shutdown();
    
     executorService3.shutdown();
    
     executorService4.shutdown();
    
     executorService5.shutdown();
    
     }
    
 }
    
 复制代码
    
    
    
    
    AI写代码

然后运行查看,结果图如下:

运行的时间差不多。

然后看一下计算密集型:

复制代码
 package org.example.objectsize;

    
  
    
 import java.util.concurrent.CountDownLatch;
    
 import java.util.concurrent.ExecutorService;
    
 import java.util.concurrent.Executors;
    
 import java.util.concurrent.atomic.AtomicLong;
    
  
    
 public class IOTest {
    
  
    
     public static void main(String[] args) throws Exception{
    
     extracted();
    
     main1(args);
    
     }
    
  
    
     private static void extracted() throws InterruptedException {
    
     final AtomicLong integer = new AtomicLong();
    
     ExecutorService executorService = Executors.newFixedThreadPool(50);
    
     CountDownLatch latch =  new CountDownLatch(50);
    
     long l = System.currentTimeMillis();
    
     for(int i = 0; i < 50; ++i){
    
         executorService.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                 }while (integer.getAndIncrement() < 10000000L);
    
                 latch.countDown();
    
             }
    
         });
    
     }
    
     latch.await();
    
     System.out.println("大线程池:"+(System.currentTimeMillis()-l));
    
     executorService.shutdown();
    
     }
    
     public static void main1(String[] args) throws Exception{
    
     final AtomicLong integer = new AtomicLong();
    
     ExecutorService executorService1 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService2 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService3 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService4 = Executors.newFixedThreadPool(10);
    
     ExecutorService executorService5 = Executors.newFixedThreadPool(10);
    
     CountDownLatch latch =  new CountDownLatch(50);
    
     long l = System.currentTimeMillis();
    
     for(int i = 0; i < 10; ++i){
    
         executorService1.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
  
    
                 }while (integer.getAndIncrement() < 10000000L);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService2.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
  
    
                 }while (integer.getAndIncrement() < 10000000L);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService3.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
  
    
                 }while (integer.getAndIncrement() < 10000000L);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService4.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
  
    
                 }while (integer.getAndIncrement() < 10000000L);
    
                 latch.countDown();
    
             }
    
         });
    
         executorService5.execute(new Runnable() {
    
             @Override
    
             public void run() {
    
                 do{
    
                     
    
                 }while (integer.getAndIncrement() < 10000000L);
    
                 latch.countDown();
    
             }
    
         });
    
     }
    
     latch.await();
    
     System.out.println("多线程池:"+(System.currentTimeMillis()-l));
    
     executorService1.shutdown();
    
     executorService2.shutdown();
    
     executorService3.shutdown();
    
     executorService4.shutdown();
    
     executorService5.shutdown();
    
     }
    
 }
    
  
    
 复制代码
    
    
    
    
    AI写代码

运行结果:

从中会发现两者之间的结果相差不多。

从上面两个例子可以知道,多线程和大线程池两者其实都差不多

2. 大线程池和多线程池选择原则

在大多数开源项目的实践中,每个任务类别都应配备独立 dedicated的线程池以避免资源冲突.原因分析如下:每个任务类别都需要专用 dedicated的资源分配机制,若共享同一线程池可能导致性能瓶颈或数据竞争.因此,将每个任务类型与独立 dedicated的线程池绑定是一种合理的做法

  • 独立线程池能够不影响各类别任务作业之间的相互影响作用,并从而有助于保证各任务作业的独立性与完整性。
  • 共享一个线程池可能存在的问题是:
    • 不同类别的作业运行所需时间长短不一,在这种情况下会导致各类型作业占用线程的时间长度也不一。
    • 当某一类作业运行时间较长但其被调用频率较低时,在这种情况下可能导致其他类型作业长时间停滞在队列等待获取执行机会的状态下而无法正常运行。
  • 线程池中的线程数量难以确定是否适合所有类别任务共同使用的情况将会使得资源估算变得异常复杂。如果设置过少则可能导致资源不足的问题;如果设置过多则会因为频繁切换而导致大量浪费在线程切换上。对于IO密集型的任务可能还能勉强接受但对于计算密集型的任务就未必如此友好了。
  • 不同类型的作业由于运行时长差异导致了资源分配趋于不均衡状态有的作业可能根本无法及时获得资源而长时间停滞在队列等待状态中当队列中的作业数量不断增加时这可能会最终耗尽JVM内存空间而导致应用崩溃。
  • 在错误诊断与排查的过程中而言采用多线程池的方式则更加有助于发现并定位问题所在从而提高故障处理效率。

3. 总结

每个线程池最好专注于单一任务,在某些情况下(比如某个类型的的任务出现延迟问题时),建议通过心跳机制维持某种状态以应对延迟执行导致的服务端连接失效的问题,并将其剔除以避免影响系统稳定性)。然而,在实际应用中,并非所有场景都适合直接应用这种机制;选择合适的解决方案才是最优的选择

全部评论 (0)

还没有任何评论哟~