java线程池

1、Executor线程池框架

  JDK1.5引入了Executor线程池框架,通过它把任务的提交和执行进行解耦,我们只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行、被哪个线程执行,以及什么时候执行。

  java.util.concurrent.Executor: 大部分线程池相关的接口都是实现这个接口的

public interface Executor {

    void execute(Runnable command);

}

该接口的继承实现有:

工作中常见到的是上面我圈起来的两个东西,当我们去看源码后,可以发现其实ThreadPoolExecutor也继承至ExecutorService(如下图所示)。顾名思义ExecutorService就是提供线程服务的接口。

2、初始化一个ExecutorService

ExecutorService defaultExecutorService = new ThreadPoolExecutor(corePoolSize,
                                                             maxPoolSize,
                                                             keepAliveTime,
                                                             timeUnit,
                                                             workQueue,
                                                             threadFactory,handle);

方法参数:
   corePoolSize:核心线程数
   maxPoolSize:最大线程数
     keepAliveTime:线程存活时间(在corePore<*<maxPoolSize情况下有用)
     timeUnit:存活时间的时间单位
     workQueue:阻塞队列(用来保存等待被执行的任务)

注:关于workQueue参数的取值,JDK提供了4种阻塞队列类型供选择:
        ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
        inkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任;

             SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直                                                    处于阻塞状态,吞吐量通常要高于ArrayBlockingQuene;

        PriorityBlockingQuene:具有优先级的无界阻塞队列

     threadFactory:线程工厂,主要用来创建线程;

     handler:表示当拒绝处理任务时的策略,有以下四种取值

 注: 当线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:

    ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

    ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。

    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

    ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

    当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。

3、4种类型的线程池

其实除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,timeUnit,workQueue,threadFactory,handle)实现的,只是参数不同而已。

1)newFixedThreadPool()
   说明:初始化一个指定线程数的线程池,其中corePoolSize == maxiPoolSize,使用LinkedBlockingQuene作为阻塞队列
   特点:即使当线程池没有可执行任务时,也不会释放线程。

//构造源码
public static ExecutorService newFixedThreadPool(int nThreads) { 
        return new ThreadPoolExecutor(nThreads, nThreads, 0L,
                                      TimeUnit.MILLISECONDS, 
                                      new LinkedBlockingQueue<Runnable>()); 
} 

2)newCachedThreadPool()
    说明:初始化一个可以缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
    特点:在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源;当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;因此,使用时要注意控制并发的任务数,防止因创建大量的线程导致而降低性能。

//构造源码
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}

3)newSingleThreadExecutor()
    说明:初始化只有一个线程的线程池,内部使用LinkedBlockingQueue作为阻塞队列。
    特点:如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行

//构造源码
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
}

4)newScheduledThreadPool()
      特定:初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使用该线程池定期的同步数据。

     总结:除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor类(Executor的子类)实现的。

//构造源码
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

4、给大家分享一个Executor工具类:

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolUtil {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolUtil.class);
    
    private static final int THREAD_SIZE = 20;
    
    private static final int MAXIMUM_POOL_SIZE = 200;
    
    private static final int WORKER_QUEUE_SIZE = 1024;
    
    private static final int KEEP_ALIVE_TIME = 0;
    
    private static final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("yf-pool-%d").build();
    
    private static final ExecutorService defaultExecutorService = new ThreadPoolExecutor(
            THREAD_SIZE,
            MAXIMUM_POOL_SIZE,
            KEEP_ALIVE_TIME,
            TimeUnit.MINUTES,
            new LinkedBlockingQueue<>(WORKER_QUEUE_SIZE),
            threadFactory, new ThreadPoolExecutor.AbortPolicy());
    /**
     * 使用默认线程池处理单个任务,不等待处理完成就返回
     * @param task
     */
    public static void execOneTaskWithNoWait(Runnable task)
    {
        execTaskListWithNoWait(defaultExecutorService,new ArrayList<Runnable>(){{add(task);}});
    }
    
    /**
     * 使用业务特定线程池处理单个任务,不等待处理完成就返回
     * @param task
     */
    public static void execOneTaskWithNoWait(ExecutorService threadPool, Runnable task)
    {
        execTaskListWithNoWait(threadPool,new ArrayList<Runnable>(){{add(task);}});
    }
    
    /**
     * 使用默认线程池处理任务,不等待处理完成就返回
     * @param taskList
     */
    public static void execTaskListWithNoWait(List<Runnable> taskList)
    {
        execTaskListWithNoWait(defaultExecutorService,taskList);
    }
    
    /**
     * 使用业务特定线程池处理,不等待处理完成就返回
     * @param threadPool
     * @param taskList
     */
    public static void execTaskListWithNoWait(ExecutorService threadPool, List<Runnable> taskList)
    {
        if(threadPool==null || CollectionUtils.isEmpty(taskList))
        {
            return;
        }
        for(Runnable task : taskList)
        {
            threadPool.execute(() -> doTask(task));
        }
    }
    
    private static void doTask(Runnable task) {
        try {
            task.run();
        } catch (Exception e) {
            LOGGER.error("parallelExecWithNoWait run task error!",e);
        }
    }
    
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程池是一种用于管理和复用线程的机制,它可以提高多线程应用程序的性能和效率。线程池中的线程可以被重复使用,避免了频繁创建和销毁线程的开销。 在Java中,线程池可以通过`ExecutorService`接口来创建和管理。线程池中的线程可以执行提交给它的任务,并且可以根据需要自动创建新的线程或销毁闲置的线程。 嵌套线程池是指在一个线程池中创建另一个线程池。这种情况通常发生在需要处理一些复杂的任务,其中每个任务本身也需要使用线程池来执行。 下面是一个示例代码,演示了如何在Java中嵌套使用线程池: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class NestedThreadPoolExample { public static void main(String[] args) { // 创建外层线程池 ExecutorService outerThreadPool = Executors.newFixedThreadPool(5); // 提交任务给外层线程池 outerThreadPool.execute(() -> { // 创建内层线程池 ExecutorService innerThreadPool = Executors.newFixedThreadPool(3); // 提交任务给内层线程池 innerThreadPool.execute(() -> { // 内层线程池执行的任务 System.out.println("Inner thread pool task executed"); }); // 关闭内层线程池 innerThreadPool.shutdown(); }); // 关闭外层线程池 outerThreadPool.shutdown(); } } ``` 在上面的示例中,我们首先创建了一个外层线程池`outerThreadPool`,它使用`Executors.newFixedThreadPool()`方法创建了一个固定大小的线程池。然后,我们向外层线程池提交了一个任务,该任务在执行时创建了一个内层线程池`innerThreadPool`,并向内层线程池提交了一个任务。最后,我们分别关闭了内层线程池和外层线程池

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值