线程池(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. k8s-in-aciton-3

    镜像构建过程 构建过程不是由Docker客户端进行的,而是将整个目录的文件上传到Docker守护进程并在那里进行的.Docker客户端和守护进程不要求在同一 台机器上.如果你在一台非Linux操作系统 ...

  2. vue实现v-model父子组件间的双向通信

    首先讲清楚有个缺点:父页面若同时使用多个子组件,永远只会只能实现第一个双向驱动,我是新手,还在研究.如果有高手请指教,感谢! 子组件 <script> export default { m ...

  3. 51 Nod 1134 最长递增子序列(经典问题回顾)

    1134 最长递增子序列  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元 ...

  4. 51 Nod Bash 游戏v2

    1067 Bash游戏 V2  基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  取消关注 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次只能拿1,3 ...

  5. unittest详解(五) 引入装饰器@classmethod

    我们知道setUp()和setDown()的作用是在每条测试用例执行前准备测试环境以及用例测试结束后恢复测试环境,如果我们执行的测试类下所有测试用例的环境准备和环境复原的操作都是一样的,那么我们就没必 ...

  6. 【Java基础】谈谈集合.List

    摘自:https://www.cnblogs.com/54chensongxia/p/11722828.html 目录 1. ArrayList 1.1 ArrayList的构造 1.2 add方法 ...

  7. shiro的Quickstart

    /** * Simple Quickstart application showing how to use Shiro's API. * * @since 0.9 RC2 */ public cla ...

  8. 选题 Scrum立会报告+燃尽图 04

    本次作业要求参见:edu.cnblogs.com/campus/nenu/2019fall/homework/9913 一.小组情况组长:贺敬文组员:彭思雨 王志文 位军营 徐丽君队名:胜利点 二.S ...

  9. php 发送邮件(1)代码逻辑

    tp3.2 使用phpmailer发送短信邮箱 准备工作 1.thinkphp3.2 2.qq邮箱(开通过POP3/SMTP服务)在qq邮箱内,设置->账户->POP3/IMAP/SMTP ...

  10. spark MLlib 概念 1:相关系数( PPMCC or PCC or Pearson's r皮尔森相关系数) and Spearman's correlation(史匹曼等级相关系数)

    皮尔森相关系数定义: 协方差与标准差乘积的商. Pearson's correlation coefficient when applied to a population is commonly r ...