java 线程池实现原理

ThreadPoolExecutor 继承了 AbstractExecutorService,成员变量 ctl 是个 Integer 的原子变量用来记录线程池状态 和 线程池中线程个数,类似于 ReentrantReadWriteLock 使用一个变量存放两种信息。

//用来标记线程池状态(高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;

线程池状态含义:
RUNNING:接受新任务并且处理阻塞队列里的任务;
SHUTDOWN:拒绝新任务但是处理阻塞队列里的任务;
STOP:拒绝新任务并且抛弃阻塞队列里的任务,同时会中断正在处理的任务;
TIDYING:所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为 0,将要调用 terminated 方法;
TERMINATED:终止状态,terminated方法调用完成以后的状态。
线程池状态转换:
1.RUNNING -> SHUTDOWN:显式调用 shutdown() 方法,或者隐式调用了 finalize(),它里面调用了 shutdown() 方法。
2.RUNNING or SHUTDOWN -> STOP:显式调用 shutdownNow() 方法时候。
3.SHUTDOWN -> TIDYING:当线程池和任务队列都为空的时候。
4.STOP -> TIDYING:当线程池为空的时候。
5.TIDYING -> TERMINATED:当 terminated() hook 方法执行完成时候。

线程池参数:
corePoolSize:线程池核心线程个数;
workQueue:用于保存等待执行的任务的阻塞队列;比如基于数组的有界 ArrayBlockingQueue,基于链表的无界 LinkedBlockingQueue,最多只有一个元素的同步队列 SynchronousQueue,优先级队列 PriorityBlockingQueue 等。
maximunPoolSize:线程池最大线程数量。
ThreadFactory:创建线程的工厂。
RejectedExecutionHandler:饱和策略,当队列满了并且线程个数达到 maximunPoolSize 后采取的策略,比如 AbortPolicy (抛出异常),CallerRunsPolicy(使用调用者所在线程来运行任务),DiscardOldestPolicy(调用 poll 丢弃一个任务,执行当前任务),DiscardPolicy(默默丢弃,不抛出异常)。
keeyAliveTime:存活时间。如果当前线程池中的线程数量比核心线程数量要多,并且是闲置状态的话,这些闲置的线程能存活的最大时间。
TimeUnit,存活时间的时间单位。

线程池的实现主要依赖以下以下类和方法:
Worker:实现了Runnable接口用于实现线程复用,线程执行的载体
addWorker:添加一个worker执行线程
RunWorker:执行worker中线程的run方法

worker中有一个Thread类的成员变量,这个线程就是worker要执行的线程。 runworker中是一个while循环,只要存在task或者可以获取到新的task就会继续执行

private final class Worker implements Runnable {
 
	final Thread thread;
 
	Runnable firstTask;
 
	Worker(Runnable firstTask) {
		this.firstTask = firstTask;
		this.thread = getThreadFactory().newThread(this);
	}
 
	public void run() {
		runWorker(this);
	}
 
	final void runWorker(Worker w) {
		Runnable task = w.firstTask;
		w.firstTask = null;
		while (task != null || (task = getTask()) != null){
		task.run();
	}
}
private Runnable getTask() {
    if(一些特殊情况) {
        return null;
    }
 
    Runnable r = workQueue.take();
 
    return r;
}
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
 
     int c = ctl.get();
    // 当前线程数 < corePoolSize
    if (workerCountOf(c) < corePoolSize) {
        // 直接启动新的线程。
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
 
    // 活动线程数 >= corePoolSize
    // runState为RUNNING && 队列未满
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 再次检验是否为RUNNING状态
        // 非RUNNING状态 则从workQueue中移除任务并拒绝
        if (!isRunning(recheck) && remove(command))
            reject(command);// 采用线程池指定的策略拒绝任务
        // 两种情况:
        // 1.非RUNNING状态拒绝新的任务
        // 2.队列满了启动新的线程失败(workCount > maximumPoolSize)
    } else if (!addWorker(command, false))
        reject(command);
}
private boolean addWorker(Runnable firstTask, boolean core) {
 
    int wc = workerCountOf(c);
    if (wc >= (core ? corePoolSize : maximumPoolSize)) {
        return false;
    }
 
    w = new Worker(firstTask);
    final Thread t = w.thread;
    t.start();
}

线程池其实就是一个AQSplus,目的同样都是为了管理多个线程的线程状态以期提高程序对cpu的使用效率。二者有着类似的设计思想,都拥有一个既能表状态又能表数量的成员变量、一个用于承载线程对象的载体节点元素、一个用于存放等待队列的队列。
差别只是线程池的状态变量更复杂用atuomicInteger修饰前三位表线程池状态后29位表线程个数。AQS只是一个被voliter修饰的integer
线程池使用worker承载线程 works是是一个hashSet
所谓线程池本质是一个hashSet。多余的任务会放在阻塞队列中。

总结

所谓线程池本质是一个hashSet。多余的任务会放在阻塞队列中。

只有当阻塞队列满了后,才会触发非核心线程的创建。所以非核心线程只是临时过来打杂的。直到空闲了,然后自己关闭了。

线程池提供了两个钩子(beforeExecute,afterExecute)给我们,我们继承线程池,在执行任务前后做一些事情。

线程池原理关键技术:锁(lock,cas)、阻塞队列、hashSet(资源池)

https://www.cnblogs.com/rinack/p/9888717.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java线程池实现原理主要涉及以下几个关键组件: 1. 任务队列(Task Queue):用于存储待执行的任务。线程池中的线程从任务队列中获取任务并执行。 2. 线程池管理器(ThreadPool Manager):负责创建、管理和销毁线程池。它会根据配置的参数(如线程池大小、最大线程数、线程空闲时间等)来控制线程池的行为。 3. 线程池(Thread Pool):由一组复用的线程组成。线程池中的线程可以重复使用,避免了频繁创建和销毁线程的开销。 4. 工作线程(Worker Thread):线程池中的每个线程都是一个工作线程,负责执行从任务队列中获取的任务。 线程池实现原理如下: 1. 初始化线程池线程池管理器根据配置参数初始化一定数量的工作线程,并将它们加入线程池中。 2. 提交任务:当有任务需要执行时,将任务提交给线程池管理器。 3. 任务队列管理:线程池管理器将任务添加到任务队列中。 4. 工作线程执行任务:空闲的工作线程从任务队列中获取任务,并执行任务。 5. 监控线程状态:线程池管理器会监控工作线程的状态,如空闲时间、线程池大小等。 6. 线程回收:当线程池中的线程空闲时间超过设定的阈值时,线程池管理器可能会销毁一些空闲的线程,以减少资源占用。 Java线程池实现原理可以优化多线程的管理和资源利用,避免了频繁创建和销毁线程的开销,提高了系统的性能和稳定性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值