java基础-多线程二
java基础-多线程二
继承thread和实现Runnable的多线程每次都需要经历创建和销毁的过程,频繁的创建和销毁大大影响效率,线程池的诞生就可以很好的解决这一个问题,线程池可以充分的利用线程进行任务调度,重复利用
1. 线程池Executor与Executors
Executor为concurrent包下的线程顶级接口,提供了一个execute方法,参数为Runnable的实例
void execute(Runnable command);

Executors负责创建不同功能的线程池,线程工厂的角色,都是返回ExecutorService
2. 线程池的日常使用
2.1 newFixedThreadPool:创建指定大小的线程池,当有新任务提交时,如果线程池存在空闲则立即执行,反之则会加入阻塞队列中进行等待,等待唤醒并执行;适用于多任务异步执行
// 创建一个10个活跃线程池
ExecutorService service = Executors.newFixedThreadPool(10);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2.2 newSingleThreadExecutor: 只有一个线程的线程池,在发生异常的时候会创建一个新的线程池继续执行, 返回FinalizableDelegatedExecutorService实例;核心线程数为1,最大线程数也为1,空闲线程等待时间为0,LinkedBlockingQueue无界等待队列(链表结构) 适用于单个任务执行
ExecutorService service = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public class TestSingleThreadExecutor {
static class Test implements Runnable {
private Integer num;
private String threadType;
Test(Integer param, String threadType) {
this.num = param;
this.threadType = threadType;
}
@Override
public void run() {
System.out.println(threadType + "num=" + num + "==>" + Thread.currentThread().getName() + "线程计算=" + num / (num - 2));
}
}
public static void main(String args[]) {
ExecutorService service = Executors.newSingleThreadExecutor();
ExecutorService service1 = Executors.newFixedThreadPool(4);
for (int i = 10; i >= 1; i--) {
service.execute(new Test(i, "newSingleThreadExecutor"));
// service1.execute(new Test(i, "newFixedThreadPool"));
}
}
}
// 执行结果:
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
at com.hervey.thread.TestSingleThreadExecutor$Test.run(TestSingleThreadExecutor.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
newSingleThreadExecutornum=10==>pool-1-thread-1线程计算=1
newSingleThreadExecutornum=9==>pool-1-thread-1线程计算=1
newSingleThreadExecutornum=8==>pool-1-thread-1线程计算=1
newSingleThreadExecutornum=7==>pool-1-thread-1线程计算=1
newSingleThreadExecutornum=6==>pool-1-thread-1线程计算=1
newSingleThreadExecutornum=5==>pool-1-thread-1线程计算=1
newSingleThreadExecutornum=4==>pool-1-thread-1线程计算=2
newSingleThreadExecutornum=3==>pool-1-thread-1线程计算=3
newSingleThreadExecutornum=1==>pool-1-thread-2线程计算=-1
2.3 newCachedThreadPool: 当线程池中无可用线程时,创建和任务等同数量的线程,后续有新任务进来时,如果线程池中之前执行的线程还未被回收,则不会创建新线程直接复用之前的线程(新任务的数量<=线程池中已完成单位被回收的线程),这就是cache线程池;适用于耗时较短的任务
// SynchronousQueue同步队列用来存储等待的队列
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public class TestCacheThreadPool {
static class Test implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行");
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i< 5; i++) {
service.execute(new Test());
}
Thread.sleep(2000);
System.out.println("沉睡2秒");
for (int i = 0; i < 3; i++) {
service.execute(new Test());
}
}
}
// 执行结果:
pool-1-thread-3正在执行
pool-1-thread-2正在执行
pool-1-thread-1正在执行
pool-1-thread-5正在执行
pool-1-thread-4正在执行
沉睡2秒
pool-1-thread-4正在执行
pool-1-thread-5正在执行
pool-1-thread-1正在执行
// 如果线程池中的线程可用数量小于新任务的数量,则会一直复用线程池中可用的线程,没有可用的时候则会创建新的线程
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i< 5; i++) {
service.execute(new Test());
}
Thread.sleep(2000);
System.out.println("沉睡2秒");
for (int i = 0; i < 10; i++) {
service.execute(new Test());
}
}
// 执行结果:
pool-1-thread-1正在执行
pool-1-thread-2正在执行
pool-1-thread-3正在执行
pool-1-thread-2正在执行
pool-1-thread-4正在执行
沉睡2秒
pool-1-thread-1正在执行
pool-1-thread-2正在执行
pool-1-thread-3正在执行
pool-1-thread-4正在执行
pool-1-thread-2正在执行
pool-1-thread-1正在执行
pool-1-thread-3正在执行
pool-1-thread-4正在执行
pool-1-thread-5正在执行
pool-1-thread-6正在执行
2.4 newScheduledThreadPool: 可以设置计划时间执行的线程池,类似于quartz-scheduler定时任务,可以设置延时执行,每隔多久执行一次
// 使用newScheduledThreadPool
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
// 源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//DelayedWorkQueue 延迟队列
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
ScheduledExecutorService定时方法
// 延迟执行 Runnable实例,delay延时时长,TimeUnit时间单位
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
// Callable实例
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
// Runnable实例,initialDelay:初始化延时时间, period:每隔多长时间执行,TimeUnit:时间单位
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
long period, TimeUnit unit);
// Runnable实例,initialDelay:首次延迟时间, delay:后续延迟时间执行,TimeUnit:时间单位
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
long delay, TimeUnit unit);
上述都是日常比较常见的各种线程池的用法及作用,我们需要根据我们的使用场景来灵活调用,我们可以查看下源代码,线程池是怎么创建的及各参数的具体意义
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
线程池的各参数的概念及作用
corePoolSize 初始化线程池的线程数量,只有在工作队列超过这个数值时才会创建新的线程(不超过最大线程数量)
maximumPoolSize 线程池的最大数量
keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间;可以通过设置allowCoreThreadTimeOut(true)使得核心线程有效时间到达是关闭线程
TimeUnit keepAliveTime 设置的时间单位
BlockingQueue 阻塞等待队列
ThreadFactory 线程工厂,用于创建新线程
RejectedExecutionHandler 当workQueue阻塞队列和maximumPoolSize都满了时执行拒绝策略,拒绝任务执行
CallerRunsPolicy :这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功。
AbortPolicy :对拒绝任务抛弃处理,并且抛出异常。
DiscardPolicy :对拒绝任务直接无声抛弃,没有异常信息。
DiscardOldestPolicy :对拒绝任务不抛弃,而是抛弃队列里面等待最久的一个线程,然后把拒绝任务加到队列。
3. 线程池流程图

java基础-多线程二的更多相关文章
- java基础-多线程应用案例展示
java基础-多线程应用案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.两只熊,100只蜜蜂,蜜蜂每次生产的蜂蜜量是1,罐子的容量是30,熊在罐子的蜂蜜量达到20的时候 ...
- java 基础知识二 基本类型与运算符
java 基础知识二 基本类型与运算符 1.标识符 定义:为类.方法.变量起的名称 由大小写字母.数字.下划线(_)和美元符号($)组成,同时不能以数字开头 2.关键字 java语言保留特殊含义或者 ...
- java基础(二章)
java基础(二章) 一,变量 1.变量是内存中的一个标识符号,用于存储数据 2.变量命名规则 l 必须以字母.下划线 _ .美元符号 $ 开头 l 变量中,可以包括数字 l 变量中,不能出现特 ...
- Java基础-多线程-③线程同步之synchronized
使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...
- Java基础-多线程-②多线程安全问题
什么是线程的安全问题? 上一篇 Java基础-多线程-①线程的创建和启动 我们说使用实现Runnable接口的方式来创建线程,可以实现多个线程共享资源: class Dog implements Ru ...
- Java基础十二--多态是成员的特点
Java基础十二--多态是成员的特点 一.特点 1,成员变量. 编译和运行都参考等号的左边. 覆盖只发生在函数上,和变量没关系. Fu f = new Zi();System.out.println( ...
- 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!
前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...
- JAVA基础(二)—— 常用的类与方法
JAVA基础(二)-- 常用的类与方法 1 Math类 abs ceil floor 绝对值 大于等于该浮点数的最小整数 小于等于该浮点数的最大整数 max min round 两参数中较大的 两参数 ...
- Java实习生常规技术面试题每日十题Java基础(二)
目录 1. JAVA 的反射机制的原理. 2.静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同? 3.如何将String类型转化成Number类型. 4.什 ...
随机推荐
- 任何类型的数据都向String转型
String从其定义上发现首字母大写,所以此为一个类,属于引用数据类型,但是此类属于系统的类. (1)String像普通变量一样直接通过复制的方式进行声明.字符串使用双引号括起来.两个字符串使用&qu ...
- 《css的总结》
一.span标签:能让某几个文字或者某个词语凸显出来 <p> 今天是11月份的<span>第一天</span>,地铁卡不打折了 </p> 二.字体风格 ...
- ubuntu 13.10 eclipse 菜单栏不可用的问题
最近手贱,从官网上下载了最新的版eclipse,把一原来的3.8版本替换了,然后就发现eclipse菜单栏废了,吓我一跳,以为Ubuntu又初问题,又重新弄了一次eclipse(我直接用的压缩包),上 ...
- JDK1.8源码分析01之学习建议(可以延伸其他源码学习)
序言:目前有个计划就是准备看一下源码,来提升自己的技术实力.同时现在好多面试官都喜欢问源码,问你是否读过JDK源码等等? 针对如何阅读源码,也请教了我的老师.下面就先来看看老师的回答,也许会有帮助呢. ...
- 【Java例题】4.1 级数求和1
1. 计算级数之和: y=1-1/2+1/4-1/8+...+ (-1)^(n-1)/2^(n-1). 这里的"^"表示乘方. package chapter4; import j ...
- hadoop学习(三)----hadoop2.x完全分布式环境搭建
今天我们来完成hadoop2.x的完全分布式环境搭建,话说学习本来是一件很快乐的事情,可是一到了搭环境就怎么都让人快乐不起来啊,搭环境的时间比学习的时间还多.都是泪.话不多说,走起. 1 准备工作 开 ...
- Unity工程无代码化
目的 Unity默认是将代码放入工程,这样容易带来一些问题.1. 代码和资源混合,职能之间容易互相误改.2. 当代码量膨胀到一定程度后,代码的编译时间长到无法忍受.新版的unity支持通过asmde ...
- 【linux】【qt5界面】【系统托盘图标的实现】
前言: 博主最近在做一个聊天软件,虽然技术不咋滴,但遇到点干货肯定是要跟大家分享的啦.下面就给大家分享一个qt实现程序隐藏才系统托盘的技巧. 装备: 系统:linux, qt版本:5.9.2,GCC: ...
- ABAP 查看采购订单行项目已开票金额和已清金额
FUNCTION zmm_fm_po_invence. *"----------------------------------------------------------------- ...
- 深入解析Mysql中事务的四大隔离级别及其所解决的读现象
本文详细介绍四种事务隔离级别,并通过举例的方式说明不同的级别能解决什么样的读现象.并且介绍了在关系型数据库中不同的隔离级别的实现原理. 在DBMS中,事务保证了一个操作序列可以全部都执行或者全部都不执 ...