点一点,了解更多https://www.csdn.net/

本篇文章将详细讲解什么是线程池,线程池的参数介绍,线程池的工作流程,使用Executors创建常见的线程池~~~

目录

点一点,了解更多

文章目录

一、线程池的概念

1.1线程池的目的-提高效率

二、线程池的参数介绍

2.1线程池的拒绝策略

以上四种策略要重点掌握,面试常考~~

三、线程池的工作流程

四、线程池的创建

4.1方法一 

 4.2方法二 

4.3方法三

4.4方法四

4.5方法五

4.6方法六

4.7方法七

五、模拟实现一个线程池

一、线程池的概念

简单来说,可以理解为一个“现成的池子”,里面有一定数量的线程等待工作,每次使用不用再次创建、使用完了不用马上销毁,会自动回收进池子中。类似常量池等等~~

虽然创建销毁线程比创建销毁进程更轻量, 但是在频繁创建销毁线程的时候还是会比较低效,线程池就是为了解决这个问题,如果某个线程不再使用了,并不是真正把线程释放,而是放到一个“池子”中,下次如果需要用到线程就直接从池子中取,不用再次创建。

1.1线程池的目的-提高效率

池的目的就是为了提高效率,从线程池中拿线程,属于用户态操作;而从系统再去创建线程,涉及到用户态和内核态之间的切换,真正的创建是在内核态完成的。

那么什么是用户态?什么是内核态?下面我来举个例子:

银行中有大厅和服务柜台,大厅相当于用户态,柜台相当于内核态;每个地方都有打印机,如果来客户需要办理业务,可以在打印机上办理,也可以找工作人员办理。

此时来个老哥,说想办个银行卡,但是没带身份证复印件,有俩个办法:1.自己去大厅的复印件,自己复印一份,拿过来。2.让工作人员去柜台里面的打印机,去复印下再拿回来。

那么如果自己去复印,就立即去了,立即回来了,中间不耽误;如果工作人员去复印,他可能会做点别的,确实能给你复印,但是就不一定及时了~~

结论:用户态操作,时间是可控的;涉及到内核态操作,时间就不可控了~~

二、线程池的参数介绍

先看ThreadPoolExecutor 的构造方法

重点理解一下这几个参数含义:先情景带入一下,把线程池当作公司,一类正式员工;一类实习生;

1.corePoolSize:核心线程数,相当于正式员工

2.maxinumPoolSize:最大线程数,相当于正式员工+实习生

3.

long keepAliveTime:实习生线程保持存活的时间 

当任务比较少的时候,整体比较空闲,实习生不是立即被辞退的,表示实习生最大的存活时间

4.

TimeUnit unit:单位,秒,分钟,毫秒

5. 

BlockingQueue workQueue:线程池里要管理很多任务,这些任务也是通过阻塞队列来组织的,此时可以手动指定一个队列给线程池,此时就可以很方便的获取队列中的信息

6.

ThreadFactory threadFactory:工厂模式,创建线程的辅助的类

7.

RejectedExecutionHandler handler:线程池的拒绝策略,如果任务量超出公司的负荷接下来该怎么处理

2.1线程池的拒绝策略

上述四种是标准库中提供的四种拒绝策略:

1.

表示如果队列满了,继续添加任务, 添加操作之间抛出异常(新老都执行不了,哭)

2.

添加的线程自己负责执行这个任务(怼回去)

3.

丢弃最老的任务

4. 丢弃最新的任务 

以上四种策略要重点掌握,面试常考~~

三、线程池的工作流程图

四、线程池的创建

ExecutorService 表示一个线程池实例Executors 是一个工厂类, 能够创建出几种不同风格的线程池ExecutorService 的 submit 方法能够向线程池中提交若干个任务Executors 本质上是 ThreadPoolExecutor 类的封装

4.1方法一 

创建具有十个线程的线程池(大小固定)

public class ThreadDemo {

public static void main(String[] args) {

ExecutorService pool = Executors.newFixedThreadPool(10);

pool.submit(new Runnable() {

@Override

public void run() {

System.out.println("hello");

}

});

}

}

 4.2方法二 

创建一个操作无界队列且只有一个工作线程的线程池

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

4.3方法三

用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将收回并移出缓存,创建线程数目动态增长的线程池

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

4.4方法四

创建一个单线程执行器,可以在给定时间后执行或定期执行。

ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

4.5方法五

创建一个指定大小的线程池,可以在给定时间后执行或定期执行,是进阶版的Timer

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

4.6方法六

 创建一个指定大小(不传入参数,为当前机器CPU核心数)的线程池,并行地处理任务,不保证处理顺序

Executors.newWorkStealingPool();

4.7方法七

自定义线程池,工作中使用这种方法创建线程池

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,

10,

10000,

TimeUnit.MILLISECONDS,

new LinkedBlockingQueue());

五、模拟实现一个线程池

设置一个具有十个线程的线程池,打印0-1000个数。

其中在构造方法中调用十个线程执行,submit方法进行放入任务!!

class MyThreadPool{

private BlockingQueue queue = new LinkedBlockingQueue<>();

public void submit(Runnable runnable) throws InterruptedException {

queue.put(runnable);

}

public MyThreadPool(int n){

for (int i = 0; i < n; i++) {

Thread t = new Thread(() -> {

try {

while (true){

Runnable runnable = queue.take();

runnable.run();

}

} catch (InterruptedException e) {

e.printStackTrace();

}

});

t.start();

}

}

}

public class ThreadDemo {

public static void main(String[] args) throws InterruptedException {

MyThreadPool pool = new MyThreadPool(10);

for (int i = 0; i < 1000; i++) {

int number = i;

pool.submit(new Runnable() {

@Override

public void run() {

System.out.println("hello "+ number);

}

});

}

Thread.sleep(3000);

}

}

可见,线程池中任务的执行的顺序和添加顺序不一定相同,因为这十个线程是无序调度的

好文阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: