线程池(Thread Pool):把一个或多个线程通过统一的方式进行调度和重复使用的技术,避免了因为线程过多而带来使用上的开销

优点:(面试题)
可重复使用已有线程,避免对象创建、消亡和过度切换的性能开销。
避免创建大量同类线程所导致的资源过度竞争和内存溢出的问题。
支持更多功能,比如延迟任务线程池(newScheduledThreadPool)和缓存线程池(newCachedThreadPool)等。

创建方式:
有两种:ThreadPoolExecutor 和 Executors

1、ThreadPoolExecutor 的使用

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(100));
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
// 执行线程池
System.out.println("Hello, Java.");
}
});

ThreadPoolExecutor构造方法:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);

构造参数说明

//① corePoolSize
//线程池中的核心线程数,默认情况下核心线程一直存活在线程池中,
// 如果将 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设为 true,
// 如果线程池一直闲置并超过了 keepAliveTime 所指定的时间,核心线程就会被终止。

//② maximumPoolSize
// 线程池中最大线程数,如果活动的线程达到这个数值以后,后续的新任务将会被阻塞(放入任务队列)。

//③ keepAliveTime
//线程池的闲置超时时间,默认情况下对非核心线程生效,如果闲置时间超过这个时间,非核心线程就会被回收。
// 如果 ThreadPoolExecutor 的 allowCoreThreadTimeOut 设为 true 的时候,核心线程如果超过闲置时长也会被回收。

//④ unit
//配合 keepAliveTime 使用,用来标识 keepAliveTime 的时间单位。

// ⑤ workQueue
// 线程池中的任务队列,使用 execute() 或 submit() 方法提交的任务都会存储在此队列中。

//⑥ threadFactory 为线程池提供创建新线程的线程工厂。

//⑦ rejectedExecutionHandler
//线程池任务队列超过最大值之后的拒绝策略,RejectedExecutionHandler 是一个接口,里面只有一个 rejectedExecution 方法,可在此方法内添加任务超出最大值的事件处理。ThreadPoolExecutor 也提供了 4 种默认的拒绝策略:
//new ThreadPoolExecutor.DiscardPolicy():丢弃掉该任务,不进行处理
//new ThreadPoolExecutor.DiscardOldestPolicy():丢弃队列里最近的一个任务,并执行当前任务
//new ThreadPoolExecutor.AbortPolicy():直接抛出 RejectedExecutionException 异常
//new ThreadPoolExecutor.CallerRunsPolicy():既不抛弃任务也不抛出异常,直接使用主线程来执行此任务

代码演示:

(1)test1

public static void test1() throws ExecutionException, InterruptedException {
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(1, 1, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(2));
threadPoolExecutor.allowCoreThreadTimeOut(true); //线程池执行方法 execute()
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-Hello java!");
}
}); //线程池执行方法 submit() 可以接收线程池执行的返回值。
Future<Object> future = threadPoolExecutor.submit(new Callable<Object>() {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName()+"-Hello china!");
return "success";
}
});
System.out.println(future.get());
}

(2)test2

public static void test2(){
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,10,10L,TimeUnit.SECONDS,
new LinkedBlockingQueue(2),new MyThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
for(int i=0;i<10;i++){
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" wake up!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
static class MyThreadFactory implements ThreadFactory{
private AtomicInteger count = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("myThread"+count.addAndGet(1));
return t;
}
}

(3)test3

//shutdown & shutdownNow
//shutdown():不会立即终止线程池,而是要等所有任务队列中的任务都执行完后才会终止。执行完 shutdown 方法之后,线程池就不会再接受新任务了。
//shutdownNow():执行该方法,线程池的状态立刻变成 STOP 状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,执行此方法会返回未执行的任务。
public static void test3(){
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,10,10,TimeUnit.SECONDS,new LinkedBlockingDeque<>(10));
threadPoolExecutor.execute(()->{
for (int j=0; j<5 ;j++){
System.out.println("i m " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
});
// threadPoolExecutor.shutdown();
threadPoolExecutor.shutdownNow(); threadPoolExecutor.execute(()->{
System.out.println("i m stop!");
});
}

(4)test4

public static void test4(){
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,1,10,TimeUnit.SECONDS,new LinkedBlockingDeque<>(1),new ThreadPoolExecutor.DiscardPolicy());
threadPoolExecutor.allowCoreThreadTimeOut(true);
for (int i=0;i<10;i++) {
threadPoolExecutor.execute(() -> {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "wake up!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
} //线程池第 1 次执行任务时,会新创建任务并执行;第 2 次执行任务时,因为没有空闲线程所以会把任务放入队列;
//第 3 次同样把任务放入队列,因为队列最多可以放两条数据,所以第 4 次之后的执行都会被舍弃(没有定义拒绝策略),于是就打印了 3 次线程名称。

总结:

线程池的工作原理:
当线程池中有任务需要执行时,线程池会判断如果线程数量没有超过核心数量就会新建线程池进行任务执行,
如果线程池中的线程数量已经超过核心线程数,这时候任务就会被放入任务队列中排队等待执行;
如果任务队列超过最大队列数,并且线程池没有达到最大线程数,就会新建线程来执行任务;
如果超过了最大线程数,就会执行拒绝执行策略。
线程池可通过 submit() 来调用执行,从而获得线程执行的结果,也可以通过 shutdown() 来终止线程池。

java学习笔记 - 线程池(一)的更多相关文章

  1. Java学习笔记 线程池使用及详解

    有点笨,参考了好几篇大佬们写的文章才整理出来的笔记.... 字面意思上解释,线程池就是装有线程的池,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程 ...

  2. java学习之线程池的实现

    package com.gh.threadpoor; import java.util.concurrent.ExecutorService; import java.util.concurrent. ...

  3. Java学习:线程池

    线程池 线程池概念:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多的资源. 线程池:容器-->集合(ArrayList,Hash ...

  4. 【多线程】Android多线程学习笔记——线程池

    Java线程池采用了享元设计模式,在系统中维持一定数量的线程,用于处理异步或并发需求,在平时处理异步或并发任务时被广泛使用.这里基于JDK1.8和Android28来整理一些关于线程池的知识点. 一. ...

  5. Java 学习笔记 线程控制

    题目一 本质上来说,线程是不可控制的,线程的执行是由CPU资源分配决定的,我们无法干预系统CPU的资源分配,但我们可以增加条件来让线程按照我们的预想顺序来执行. 比如.如果当前的执行的线程不满足我们所 ...

  6. java学习笔记 线程的实现与同步

    2019.4.2 线程实现的两种方式 继承线程,复写其中的run方法 实现runnable接口,复写run方法 使用: MyThread target = new MyThread(); new Th ...

  7. Java学习笔记--线程day01

    线程的概念:一个线程是进程的顺序执行流: 同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈.线程在切换时负荷小,因此,线程也被称为轻负荷进程.一个进程中可以有多个线程. ...

  8. Java学习笔记——线程

    线程: 定义:线程是程序内的一个单一的顺序控制流程,也被称为“轻型进程(lightweight process)” 或“执行上下文(execution context )” 线程用于分隔任务 线程类似 ...

  9. java学习笔记14--多线程编程基础1

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...

随机推荐

  1. ueditor+实现word图片自动上传

    最近公司做项目需要实现一个功能,在网页富文本编辑器中实现粘贴Word图文的功能. 我们在网站中使用的Web编辑器比较多,都是根据用户需求来选择的.目前还没有固定哪一个编辑器 有时候用的是UEditor ...

  2. BZOJ 4154: [Ipsc2015]Generating Synergy KDtree+dfs序

    多组数据真tm恶心~ 把 $dfs$序和深度分别看作横纵坐标,然后用 $KDtree$ 数点就可以了~ #include <cstdio> #include <cstring> ...

  3. mv:移动文件或改名

    mv 命令(move 的缩写),既可以在不同的目录之间移动文件或目录,也可以对文件和目录进行重命名.该命令的基本格式如下: mv [选项] 源文件 目标文件 选项: -f:强制覆盖,如果目标文件已经存 ...

  4. Python黑科技神奇去除马赛克

    图片修复程序-可用于水印去除 在现实的生活中,我们可能会遇到一些美好的或是珍贵的图片被噪声干扰,比如旧照片的折痕,比如镜头上的灰尘或污渍,更或者是某些我们想为我所用但有讨厌水印,那么有没有一种办法可以 ...

  5. JavaWeb_Get和Post方法传输数据区别

    Get方法和Post方法传输数据区别: 传送门 GET在浏览器回退时是无害的,而POST会再次提交请求 GET产生的URL地址可以被Bookmark,而POST不可以 GET请求会被浏览器主动cach ...

  6. R_Studio读取xls文件

    百度经验 传送门 需要包xlsx 依赖包rjava 需要安装java编译环境 在R Console中执行命令install.packages("rjava"),install.pa ...

  7. 微信小程序_(组件)组件基础

    (progress.text.block) 组件基础效果 官方文档:传送门 Page({ /** * 页面的初始数据 */ data: { text:"Gary 微信小程序\n", ...

  8. conda查看某个安装包的依赖项

    查看某个安装包XXX的依赖项的conda指令为: conda search XXX -info 比如XXX为pytorch0.3.1,就会有如下输出: pytorch 0.3.1 py36hfbe70 ...

  9. nodejs 配置服务器

    node 是 js 的运行的后台环境,他自身集成了很多模块,集成的模块直接 require 就行了: npm 第三方平台,他也是为 node 服务的,对于 npm 中的模块,先 npm install ...

  10. ubuntu下mysql数据库存储路径修改

    一.安装mysql ubuntu系统安装配置APT源,apt install mysql-server mysql-client 二.查看安装端口情况 sudo netstat -tap | grep ...