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);
        }
    }
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值