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都满了时执行拒绝策略,拒绝任务执行

    1. CallerRunsPolicy :这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功。

    2. AbortPolicy :对拒绝任务抛弃处理,并且抛出异常。

    3. DiscardPolicy :对拒绝任务直接无声抛弃,没有异常信息。

    4. DiscardOldestPolicy :对拒绝任务不抛弃,而是抛弃队列里面等待最久的一个线程,然后把拒绝任务加到队列。

3. 线程池流程图

java基础-多线程二的更多相关文章

  1. java基础-多线程应用案例展示

    java基础-多线程应用案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.两只熊,100只蜜蜂,蜜蜂每次生产的蜂蜜量是1,罐子的容量是30,熊在罐子的蜂蜜量达到20的时候 ...

  2. java 基础知识二 基本类型与运算符

    java  基础知识二 基本类型与运算符 1.标识符 定义:为类.方法.变量起的名称 由大小写字母.数字.下划线(_)和美元符号($)组成,同时不能以数字开头 2.关键字 java语言保留特殊含义或者 ...

  3. java基础(二章)

    java基础(二章) 一,变量 1.变量是内存中的一个标识符号,用于存储数据 2.变量命名规则 l  必须以字母.下划线 _ .美元符号 $ 开头 l  变量中,可以包括数字 l  变量中,不能出现特 ...

  4. Java基础-多线程-③线程同步之synchronized

    使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...

  5. Java基础-多线程-②多线程安全问题

    什么是线程的安全问题? 上一篇 Java基础-多线程-①线程的创建和启动 我们说使用实现Runnable接口的方式来创建线程,可以实现多个线程共享资源: class Dog implements Ru ...

  6. Java基础十二--多态是成员的特点

    Java基础十二--多态是成员的特点 一.特点 1,成员变量. 编译和运行都参考等号的左边. 覆盖只发生在函数上,和变量没关系. Fu f = new Zi();System.out.println( ...

  7. 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!

    前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...

  8. JAVA基础(二)—— 常用的类与方法

    JAVA基础(二)-- 常用的类与方法 1 Math类 abs ceil floor 绝对值 大于等于该浮点数的最小整数 小于等于该浮点数的最大整数 max min round 两参数中较大的 两参数 ...

  9. Java实习生常规技术面试题每日十题Java基础(二)

    目录 1. JAVA 的反射机制的原理. 2.静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同? 3.如何将String类型转化成Number类型. 4.什 ...

随机推荐

  1. JavaScript Boolean(逻辑)对象

    Boolean(逻辑)对象用于将非逻辑值转换为逻辑值(true 或者 false). 实例 检查逻辑值 检查逻辑对象是 true 还是 false. 完整的 Boolean 对象参考手册 我们提供 J ...

  2. .net持续集成sonarqube篇之 sonarqube与jenkins集成(命令模式)

    系列目录 Sonarqube结合Jenkins与常见问题 我们引入sonarqube组件的最终目的是要为整个Ci环境服务的,如果不能集成于当前的Jenkins CI,那么我们做的很多关于sonarqu ...

  3. win10下nodejs的安装及配置

    这里主要引用两篇文章,写的非常详细,也能解决你可能出现的问题 nodejs安装及配置 如何删除之前nodejs设置的 npm config set prefix .....

  4. 绿色版的mysql 下载安装配置方式

    解压下载好的压缩包 下载地址 mysql-5.6.26-win64 绿色版 copy 一份my-default.ini改名字为my.ini为mysql的配置文件 打开my.ini 修改配置文件 默认的 ...

  5. java多线程核心api以及相关概念(一)

    这篇博客总结了对线程核心api以及相关概念的学习,黑体字可以理解为重点,其他的都是我对它的理解 个人认为这些是学习java多线程的基础,不理解熟悉这些,后面的也不可能学好滴 目录 1.什么是线程以及优 ...

  6. 【iOS】file not found: .../Build/Products/Debug-iphonesimulator file not found

    今天又遇到了这个问题: ld: file not found: /Users/***/Library/Developer/Xcode/DerivedData/***-dfscappaygvbougtb ...

  7. [重磅开源] 比SingleR更适合的websocket 即时通讯组件---ImCore开源了

    有感而发 为什么说 SignalR 不合适做 IM? IM 的特点必定是长连接,轮训的功能用不上. 因为它是双工通讯的设计,用hub.invoke发送命令给服务端处理业务,其他就和 ajax 差不多, ...

  8. 监控LVS

    监控LVS #!/usr/bin/python-2.6.6 #data 2017-10-17 #auth liuchao import commands,os,time #-------------- ...

  9. H3C软件开发笔试面试总结

    注:我目前是陕西师范大学计算机科学学院本科生,在西安参加笔试以及面试 先是笔试,我选择的是JAVA方向,笔试选择题目主要是一些基础性的题目,然后简答题问了final.finally.finallize ...

  10. Linux curl 命令详解

    命令概要 该命令设计用于在没有用户交互的情况下工作. curl 是一个工具,用于传输来自服务器或者到服务器的数据.「向服务器传输数据或者获取来自服务器的数据」 可支持的协议有(DICT.FILE.FT ...