本文共 2192 字,大约阅读时间需要 7 分钟。
【原创】 Java识堂
创建线程对象不像其他对象一样在JVM分配内存即可,还要调用操作系统内核的API,然后操作系统为线程分配一系列的资源,这个成本就很高了。所以线程是一个重量级对象,应该避免频繁创建和销毁
以前我们运行线程的时候new Thread().start()即可,如果线程数多了,频繁的创建线程和销毁线程很费时间。
然后Doug Lea就这样设计了一下,预先启动几个线程,还准备好一个容器。每次想执行任务时,就将实现了Runnable接口的任务放到这个容器中,预先启动好的线程不断从容器中拿出任务,调用执行Runnable接口的run方法,这样刚开始启动的线程就能执行很多次任务。大概流程就是这样,真正的线程池考虑的东西比较多。
想到没有,这就是典型的生产者-消费者模式,线程池的使用者是生产者,线程池本身是消费者。用代码来实现一下
验证代码(正常工作)
来看一下Java中的线程池类ThreadPoolExecutor的构造函数有哪些参数?
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueworkQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
来类比学习一下这些参数,我们把线程池类比为项目组,线程是这个公司的成员
corePoolSize:线程池中最少的线程数,一个项目组总得有corePoolSize人坚守阵地,都是签订劳动合同了,不能随便撤。
maximumPoolSize:当项目很忙时,就得加人,请其他项目组的人来帮忙。但是公司空间有限,最多只能加到maximumPoolSize个人。当项目闲了,就得撤人了,最多能撤到corePoolSize个人
keepAliveTime & unit:上面提到项目根据忙闲来增减人员,那在编程世界里,如何定义忙和闲呢?如果一个线程在keepAliveTime(时间数字)* unit(时间单位)时间内都没有执行任务,说明这个线程很闲。如果此时线程数大于corePoolSize,这个线程就要被回收了
workQueue:就是任务队列
threadFactory:自定义如果创建线程,例如给线程指定一个有意义的名字
handler:workQueue满了(排期满了),再提交任务,该怎么处理呢?这个就是处理策略,线程池提供了4种策略,你也可以实现RejectedExecutionHandler接口来自定义策略
现在你可以去看看jdk提供的ThreadPoolExecutor类,发现原来也没那么难理解,为了方便大家练习,我把可以粘贴的代码放上来,方便大家粘贴
public class MyThreadPool { /** 利用阻塞队列实现生产者-消费者模式 */ BlockingQueueworkQueue; /** 保存内部工作线程 */ List workThreadList = new ArrayList<>(); MyThreadPool(int poolSize, BlockingQueue workQueue) { this.workQueue = workQueue; for (int i = 0; i < poolSize; i++) { WorkThread workThread = new WorkThread(); workThread.start(); workQueue.add(workThread); } } void execute(Runnable command) { // 放入任务,如果没有空间,则阻塞等待 // try catch部分省略 workQueue.put(command); } class WorkThread extends Thread { @Override public void run() { // 循环取任务并执行 while (true) { Runnable task = null; // 获取阻塞队列的第一个任务,并删除 // 如果没有元素,则会阻塞等待 // try catch部分省略 task = workQueue.take(); task.run(); } } } public static void main(String[] args) { BlockingQueue workQueue = new LinkedBlockingQueue<>(5); MyThreadPool pool = new MyThreadPool(2, workQueue); for (int i = 0; i < 10; i++) { int num = i; pool.execute(()->{ System.out.println("线程 " + num + " 执行"); }); } }}
转载地址:http://ekggi.baihongyu.com/