java 多线程之线程池ThreadPoolExecutor

1.Java中实现线程有几种方式?

方式1:使用 Thread类或继承Thread类

1 // 创建线程对象
2 Thread t = new Thread() {
3 public void run() {
4 // 要执行的任务
5 }
6 };
7 // 启动线程
8 t.start();

方式2:实现 Runnable 接口配合Thread

1 Runnable runnable = new Runnable() {
2 public void run(){
3 // 要执行的任务
4 }
5 };
6 // 创建线程对象
7 Thread t = new Thread( runnable );
8 // 启动线程
9 t.start();

方式3:使用有返回值的 Callable

1 class CallableTask implements Callable<Integer> {
2 @Override
3 public Integer call() throws Exception {
4 return new Random().nextInt();
5 }
6 }
7 //创建线程池
8 ExecutorService service = Executors.newFixedThreadPool(10);
9 //提交任务,并用 Future提交返回结果
10 Future<Integer> future = service.submit(new CallableTask());

方式4:使用 lambda

1 new Thread(()> System.out.println(Thread.currentThread().getName())).start();

*本质上Java中实现线程只有一种方式,都是通过new Thread()创建线程,调用Thread#start启
动线程最终都会调用Thread#run方法

线程池ThreadPoolExecutor原理剖析*

成员变量ctl是Integer的原子变量,使用一个变量同时记录线程池状态和线程池中线程个数 [线程池状态(高3位),线程个数(低29位)],假设计算机硬件的Integer类型是32位二进制标示,如下面代码所示,其中高3位用来表示线程池状态,后面29位用来记录线程池线程个数

//用来标记线程池状态(高3位),线程个数(低29位)
//默认是RUNNING状态,线程个数为0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

//线程个数掩码位数,并不是所有平台int类型是32位,所以准确说是具体平台下Integer的二进制位数-3后的剩余位数才是线程的个数
private static final int COUNT_BITS = Integer.SIZE - 3;

//线程最大个数(低29位)00011111111111111111111111111111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

线程池的主要状态

//(高3位):11100000000000000000000000000000
private static final int RUNNING    = -1 << COUNT_BITS;

//(高3位):00000000000000000000000000000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;

//(高3位):00100000000000000000000000000000
private static final int STOP       =  1 << COUNT_BITS;
//(高3位):01000000000000000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;

//(高3位):01100000000000000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;

线程池的参数

另外线程池是可配置的,使用者可以根据自己的需要对线程池的参数进行调整,如类图中线程池提供了可供使用者配置的参数:

corePoolSize:线程池核心线程个数。

workQueue:用于保存等待执行的任务的阻塞队列,比如基于数组的有界Array-BlockingQueue、基于链表的无界LinkedBlockingQueue、最多只有一个元素的同步队列SynchronousQueue、优先级队列PriorityBlockingQueue等。

maximunPoolSize:线程池最大线程数量。

threadFactory:创建线程的工厂类。

defaultHandler:饱和策略,当队列满了并且线程个数达到maximunPoolSize后采取的策略,比如AbortPolicy(抛出异常)、CallerRunsPolicy(使用调用者所在线程来运行任务)、DiscardOldestPolicy(调用poll丢弃一个任务,执行当前任务)、DiscardPolicy(默默丢弃,不抛出异常)。

keeyAliveTime:存活时间。如果当前线程池中的线程数量比核心线程数量要多,并且是闲置状态的话,这些闲置的线程能存活的最大时间。
在这里插入图片描述
变量mainLock是独占锁,用来控制新增Worker线程时的原子性,termination是该锁对应的条件队列,在线程调用awaitTermination时用来存放阻塞的线程。

Worker继承AQS和Runnable接口,是具体承载任务的对象。Worker继承了AQS,实现了简单不可重入独占锁,其中state=0标示锁未被获取的状态,state=1标示锁已经被获取的状态,state=–1是创建Worker时默认的状态。创建时状态设置为–1是为了避免该线程在运行runWorker()方法前被中断,下面会具体讲解到。其中变量firstTask记录该工作线程执行的第一个任务,Thread是具体执行任务的线程。

提交任务到线程池的方法有下面几种

在这里插入图片描述

拒绝策略解析

在这里插入图片描述

AbortPolicy

public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }
    /**
     * 抛出RejectedExecutionException.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     * @throws RejectedExecutionException always
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

CallerRunsPolicy

public static class CallerRunsPolicy implements RejectedExecutionHandler {

    public CallerRunsPolicy() { }

    /**
     * 使用调用线程执行任务r
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}

DiscardPolicy

public static class DiscardPolicy implements RejectedExecutionHandler {
   
    public DiscardPolicy() { }

    /**
     * 什么都不做,默默丢弃提交的任务
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}

DiscardOldestPolicy

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        
        public DiscardOldestPolicy() { }

        /**
         * 丢弃线程池队列里面最老的任务,并把当前任务提交到线程池
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();//移除队首元素
                e.execute(r);//提交任务r到线程池执行
            }
        }
    }

线程池是通过池化少量线程来提供线程复用的,当调用线程向线程池中投递大量任务后,线程池可能就处于饱和状态了。所谓饱和状态是指当前线程池队列已经满了,并且线程池中的线程已经达到了最大线程个数。当线程池处于饱和状态时,再向线程池投递任务,而对于投递的任务如何处理,是由线程池拒绝策略决定的。

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值