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. 解决win10下MySQL 8.0登录Access denied for user 'root'@'localhost' (using password: YES)的问题

        近些时间在开始学MySQL,安装挺顺利的,按照网上现成的教程就能安装成功.     但是,在输入 mysql -uroot -p     再输入密码时,遇到了这个情况 Access denie ...

  2. Python3数据驱动ddt

    对于同一个方法执行大量数据的程序时,我们可以采用ddt数据驱动的方式,来对数据规范化整理及输出 一.需要使用python的ddt库,ddt,data,unpack方法 1.仅使用ddt和data,代码 ...

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

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

  4. logback使用配置

    一:logback.xml配置内容如下 <?xml version="1.0" encoding="UTF-8"?> <!-- Copyrig ...

  5. 有趣的Flex布局

    对于刚接触前端的小白,在还原页面样式的时候,往往会遇到页面布局(layout)上的问题,用着生硬的padding来固定盒子的位置,不仅代码看的沉重,还得适应各种浏览器页面,始终没有办法做到统一.接下来 ...

  6. 准时制生产(Just in Time,JIT)

    准时制生产(Just in Time,JIT)称为及时生产,出自日本丰田.         1.JIT生产方式的管理理念     JIT的基本概念事指在所需要的精确时间内,按所需要的质量和数量,生产所 ...

  7. 在 树莓派(Raspberry PI) 中使用 Docker 运行 aspnetcore/dotnetcore 应用

    本文主要利用 Microsoft 提供的 Dockerfile 进行安装. 虽然Raspberry PI 3 CPU支持 armv8 指令集 ,但是在 docker info 还是识别为 " ...

  8. JWT详解

    目录 1.前言 2.JWT的数据结构 2.1 Header 2.2 Payload 2.3 Signature 2.4 Base64URL 3. JWT的实现   1.前言 定义:JSON Web T ...

  9. FTP工具-FileZilla安装使用教程

    1.首先,百度搜索“FileZilla”,进入官网,下载地址:https://www.filezilla.cn/download/client  ,根据自己电脑配置去下载 2.下载本地,双击运行安装程 ...

  10. 控制台基于Quartz.Net组件实现定时任务调度(一)

    前言: 你曾经需要应用执行一个任务吗?比如现在有一个需求,需要每天在零点定时执行一些操作,那应该怎样操作呢? 这个时候,如果你和你的团队是用.NET编程的话,可以考虑使用Quartz.NET调度器.允 ...