什么是线程池?如何创建一个Java线程池?

一个线程池管理了一组工作线程,同时它还包括了一个用于放置等待执行的任务的队列。线程池可以避免线程的频繁创建与销毁,降低资源的消耗,提高系统的反应速度。java.util.concurrent.Executors提供了几个java.util.concurrent.Executor接口的实现用于创建线程池,其主要涉及四个角色:

  • 线程池:Executor
  • 工作线程:Worker线程,Worker的run()方法执行Job的run()方法
  • 任务Job:Runable和Callable
  • 阻塞队列:BlockingQueue 

 

 

一、 线程池Executor

  Executor及其实现类是用户级的线程调度器,也是对任务执行机制的抽象,其将任务的提交与任务的执行分离开来,核心实现类包括ThreadPoolExecutor(用来执行被提交的任务)和ScheduledThreadPoolExecutor(可以在给定的延迟后执行任务或者周期性执行任务)。

Executor的实现继承链条为:(父接口)Executor -> (子接口)ExecutorService -> (实现类)[ ThreadPoolExecutor + ScheduledThreadPoolExecutor ]。

 

二、任务Runable/Callable

  Runnable(run)和Callable(call)都是对任务的抽象,但是Callable可以返回任务执行的结果或者抛出异常。

 

三、任务执行状态Future

  Future是对任务执行状态和结果的抽象,核心实现类是furtureTask (所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值) ;

 

   

(1). 使用Callable+Future获取执行结果

 ExecutorService executor = Executors.newCachedThreadPool();
    Task task = new Task();
    Future<Integer> result = executor.submit(task);
    System.out.println("task运行结果" + result.get());    

    class Task implements Callable<Integer>{
            @Override
            public Integer call() throws Exception {
                System.out.println("子线程在进行计算");
                Thread.sleep(3000);
                int sum = 0;
                for(int i=0;i<100;i++)
                    sum += i;
                return sum;
            }

 

(2). 使用Callable + FutureTask获取执行结果

  ExecutorService executor = Executors.newCachedThreadPool();
     Task task = new Task();
     FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
     executor.submit(futureTask);  
    System.out.println("task运行结果"+futureTask.get());

    class Task implements Callable<Integer>{
            @Override
            public Integer call() throws Exception {
                System.out.println("子线程在进行计算");
                Thread.sleep(3000);
                int sum = 0;
                for(int i=0;i<100;i++)
                    sum += i;
                return sum;
            }

 

 

四、四种常用的线程池

 

(1). FixedThreadPool

  用于创建使用固定线程数的ThreadPool,corePoolSize = maxPoolSize = n(固定的含义),阻塞队列为LinkedBlockingQueue。

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

 

 

(2). SingleThreadExecutor

  用于创建一个单线程的线程池,corePoolSize = maxPoolSize = 1,阻塞队列为LinkedBlockingQueue。

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

 

(3). CachedThreadPool

  用于创建一个可缓存的线程池,corePoolSize = 0, maxPoolSize = Integer.MAX_VALUE,阻塞队列为SynchronousQueue(没有容量的阻塞队列,每个插入操作必须等待另一个线程对应的移除操作,反之亦然),是根据需求创建新线程的,需求多时,创建的就多,需求少时,JVM自己会慢慢的释放掉多余的线程。

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

 

(4). ScheduledThreadPoolExecutor

用于创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
              new DelayedWorkQueue());
    }

  

 

五、线程池的饱和策略

 

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

 

  • AbortPolicy:直接抛出异常,默认策略;
  • CallerRunsPolicy:用调用者所在的线程来执行任务;
  • DiscardOldestPolicy:丢弃阻塞队列中最老的任务,并执行当前任务;
  • DiscardPolicy:直接丢弃任务;

 

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

 

 

六、 线程池调优

 

  • 设置最大线程数,防止线程资源耗尽;
  • 使用有界队列,从而增加系统的稳定性和预警能力(饱和策略);
  • 根据任务的性质设置线程池大小:CPU密集型任务(CPU个数个线程),IO密集型任务(CPU个数两倍的线程),混合型任务(拆分)。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mushroom-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值