Java线程池总结

为什么要用线程池

1.线程池可以节约创建线程和销毁线程的时间。
2.线程池可以对线程进行管理。
3.线程池把执行机制和工作单元分离。工作单元就是Runnable和Callable,执行单元就是由Executor框架提供。

Java中的线程池

线程池的核心接口与类

核心接口是Executor和ExecutorService。ExecutorService就是线程池的接口定义。
图片来源于网络

Executor框架的结构

Executor框架主要是三个部分。
1.任务
Callable和Runnable,这两个就是任务,可以提交给线程池执行
2.任务的执行
任务执行的核心接口Executor,以及继承自Executor的ExecutorService接口。
3.异步计算的结果
Future接口和实现类FutureTask

ThreadPoolExecutor

这个类是Java中提供的线程池的线程池的具体实现。这个类的构造方法总共有4个,参数的话就更多了。这里就不列出构造方法的方法签名了,说一下主要的参数即可。
corePoolSize:核心线程池数量
maximumPoolSize:最大线程池数量
keepAliveTime:等待时间
timeUnit:等待时间的单位。
workQueue:阻塞队列
ThreadFactory:线程工厂,创建线程的。
handler:拒绝策略

拒绝策略

拒绝策略是指,当线程池添加任务失败的时候执行的策略。
默认的拒绝策略有4种拒绝策略。
AbrotPolicy:这个策略会抛出一个RejectExecutionExceptin异常。
CallRunsPolicy:这个策略会直接开一个线程将任务执行。
DiscardOldestPolicy:这个策略会移除最旧的那一个任务。
DiscardPolicy:这个策略什么都不做,直接抛弃该任务。

如何使用线程池

Java中一般有两种方式创建线程池,一种是使用Executors提供的的工厂方法,还有一种是手动创建ThreadPoolExecutor对象。推荐使用手动创建的方法,因为手动创建可以使用ThreadFactory给线程添加名字,这样有个好处,就是当出现了线上bug,需要查线程池中的线程时,可以快速定位出现问题的线程。并且自定义线程可控性更强。

手动创建线程池

package com.xymxyg.threadpool;

import java.util.concurrent.*;

/**
 * @author guangsheng.tang
 */
public class CreateThreadPool {
    public static void main(String[] args) {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(16), new ThreadPoolExecutor.DiscardPolicy());
        executor.execute(() -> {
            System.out.println("lalal");
            System.out.println("lambdaTest");
        });
        ThreadPoolExecutor newExecutor = new ThreadPoolExecutor(5, 5,
                0, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(16), r -> {
            Thread thread = new Thread(r);
            thread.setName("我的线程");
            return thread;
        });
        newExecutor.execute(() -> {
            System.out.println("啦啦啦");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                System.out.println("线程被中断");
            }
        });
        //使用线程池的时候,使用shutdown或者shutdownNow关闭线程池。
        executor.shutdown();
        newExecutor.shutdownNow();
    }
}

使用Executors工厂类创建线程池

Executors是Java提供的工厂类,提供了几个静态工厂方法,可以快速的创建线程池。这几个静态工厂方法都是通过创建ThreadPoolExecutor对象的。

newFixedThreadPool(2);

这个是固定核心线程池数的线程池。查看Executors的源码可以看出实现方法。关于阻塞队列,将在另一篇文章里介绍。

new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>())

这个线程池使用的LinkedBlockingQueue这个阻塞队列,这个队列是有限的,长度为MAX_INT_VALUE;

Executors.newCachedThreadPool();

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());

这个线程池使用的是SynchronousQueue,这个队列的特点是队列大小为0,一个插入,必须对应一个取出。这个线程池的显著特点是核心大小为0,当来了任务时,它会创建一个线程去执行,并且它会缓存线程,在60s内没有任务来到,则会被销毁。

Executors.newScheduledThreadPool(2);

这个线程池值得注意,他返回一个ScheduledExecutorService对象,可以根据时间需要对线程进行调度。使用这个线程池就不用submit或者exeuce方法了,应该使schedule,scheduleAtFixedRate或者scheduleWithFixedDelay方法。schedule方法不会立即执行这个任务,而是在延迟一定的时候后进行执行。shceduleAtFixedRate和scheduleWithFixedDelay方法会循环调度任务,

Executors.newSingleThreadScheduledExecutor();
这个线程池没有什么好说的,就是上一个线程池的单线程版本。

线程池的关闭

使用shutdown()或者shutdownNow()方法进行关闭。shutdown方法会将线程池的状态设置为shutdown状态,不允许提交新的任务,但是会等待线程池中已经提交的线程执行完毕。

shutdownNow方法设置的状态是STOP状态,不会等待线程池中的线程执行结束,它会尝试中断线程池中运行的线程,如果该线程不能响应中断,那么它可能永远也不会停止。shutdownNow方法会返回没有执行的线程。

线程池的工作原理

当提交一个Runable的时候(调用execute或者submit方法),线程池会把该Runnable封装为一个Task,如果此时线程池中的线程小于核心线程,则会创建一个新的线程进行执行,否则尝试插入到阻塞队列中,如果阻塞队列满,则会尝试创建额外线程(当线程数量小于最大线程数量的时候),如果失败,则会执行拒绝策略。

Runnable和Callable的区别

Runnable和Callable都是线程池中的执行单元,它们都可以提交到线程池中进行执行,但是他们有一点儿区别,Runnable是没有返回值的, Callable是有返回值的。并且提交Runnable是用execute方法,提交Callable是使用submit方法。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值