java学习笔记 - 线程池(一)
线程池(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学习笔记 - 线程池(一)的更多相关文章
- Java学习笔记 线程池使用及详解
有点笨,参考了好几篇大佬们写的文章才整理出来的笔记.... 字面意思上解释,线程池就是装有线程的池,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程 ...
- java学习之线程池的实现
package com.gh.threadpoor; import java.util.concurrent.ExecutorService; import java.util.concurrent. ...
- Java学习:线程池
线程池 线程池概念:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多的资源. 线程池:容器-->集合(ArrayList,Hash ...
- 【多线程】Android多线程学习笔记——线程池
Java线程池采用了享元设计模式,在系统中维持一定数量的线程,用于处理异步或并发需求,在平时处理异步或并发任务时被广泛使用.这里基于JDK1.8和Android28来整理一些关于线程池的知识点. 一. ...
- Java 学习笔记 线程控制
题目一 本质上来说,线程是不可控制的,线程的执行是由CPU资源分配决定的,我们无法干预系统CPU的资源分配,但我们可以增加条件来让线程按照我们的预想顺序来执行. 比如.如果当前的执行的线程不满足我们所 ...
- java学习笔记 线程的实现与同步
2019.4.2 线程实现的两种方式 继承线程,复写其中的run方法 实现runnable接口,复写run方法 使用: MyThread target = new MyThread(); new Th ...
- Java学习笔记--线程day01
线程的概念:一个线程是进程的顺序执行流: 同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈.线程在切换时负荷小,因此,线程也被称为轻负荷进程.一个进程中可以有多个线程. ...
- Java学习笔记——线程
线程: 定义:线程是程序内的一个单一的顺序控制流程,也被称为“轻型进程(lightweight process)” 或“执行上下文(execution context )” 线程用于分隔任务 线程类似 ...
- java学习笔记14--多线程编程基础1
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...
随机推荐
- Oracle 别名
在Oracle数据库中,给表起别名时,直接"Tablename 别名"就可以,不需要AS. 在Oracle数据库中,数据表别名是不能加AS的,例如: SELECT a.USERNA ...
- CF603E Pastoral Oddities 优先队列+结论+LCT维护生成树
首先,一个神奇的结论:一个合法的方案存在的条件是每一个联通块的节点数都是偶数个的. 这个可以用数学归纳法简单证一证. 证出这个后,我们只需动态加入每一个边,并查看一下有哪些边能够被删除(删掉后联通块依 ...
- 【UOJ#129】 【NOI2015】寿司晚宴
题目描述 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 ...
- Jmeter(五)关联之正则表达式提取器
我们在用Jmeter做接口或者性能测试时,经常会碰到第二个请求提交的的参数要从第一个请求返回的参数中获取,而这些参数值并不是固定的,是动态变化的,这种场景就要用到关联 Jmeter提供了一种叫做正则提 ...
- ar9331修改flash大小和df、cat /proc/mtd的区别
首先感谢黄工的指导. 在openwrt固件目录下target/linux/ar71xx/image/Makefile,找到对应的机型,修改为4M,8M,16M,32M. 以oolite机型为例,如图所 ...
- Boost学习
使用boost function使用类成员函数作为回调函数 #include <iostream> #include <boost/function.hpp> struct M ...
- 用过消息队列?Kafka?能否手写一个消息队列?懵
是否有同样的经历?面试官问你做过啥项目,我一顿胡侃,项目利用到了消息队列,kafka,rocketMQ等等. 好的,那请开始你的表演,面试官递过一支笔:给我手写一个消息队列!!WHAT? 为了大家遇到 ...
- oj.1677矩形嵌套,动态规划 ,贪心
#include<iostream> #include<algorithm> #include<cstring> using namespace std; stru ...
- ASP.NET中的物理路径与虚拟路径
物理路径:c:\PathsAndURLs\Content\Colors.html虚拟路径:(http://localhost:53274/Content/Colors.html)路径中端口号后面的那部 ...
- Sublime text3 Version 3.2.2, Build 3211破解
一.修改hosts hosts地址: C:\Windows\System32\drivers\etc #sublimetext 127.0.0.1 www.sublimetext.com 127.0. ...