1,为什么要使用线程池:Executors

系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互。在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。
线程池在系统启动时即创建大量空闲的线程,程序将Runnable对象或Callable对象传给线程池,线程池就会启动1个空闲的线程来执行它们的run()或者call()方法run()或call()方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个Runnable对象或者Callable对象的run()或者call()方法
 

2,线程池的基本使用:

在Java5之前开发者要实现线程池必须手动去实现。但是在Java5之后,提供了一个Executors工厂类来生产线程池,这个类提供了很多工厂方法,我们会逐一的去写。
使用线程池的流程如下:
  • (1),调用Executors静态方法newXXXX获取ExecutorService对象,该对象代表一个线程池
  • (2),创建Runnable实例或Callable实例,作为线程运行任务。
  • (3),调用ExecutorService对象的submit()方法来提交Runnable或Callable实例。
  • (4),当不想提交任务时,调用ExecutorService 对象 shutdown()方法来关闭线程池

示例:newCachedThreadPool

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @ClassName ExecutorsThreadPoolTest
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/26.
*/
public class ExecutorsThreadPoolTest {
public static void main(String[] args) {
Runnable r = () ->{
String tName = Thread.currentThread().getName();
System.out.println(tName + "运行中...");
try {
Thread.sleep(1000);
System.out.println(tName + "运行结束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int i=0; i<10; i++) {
threadPool.submit(r);
}
/**
* 如果不关闭线程池。则持续等待提交新的线程
*/
threadPool.shutdown(); //关闭线程池就无法再次submit;已submit的线程运行结束后会退出
}
}

3、创建线程池的静态方法

  • 1,ExecutorService newCachedThreadPool():创建一个具有缓存功能的线程池,系统会根据需要创建线程,这些创建的线程会缓存在线程池中,以后,如果它是空闲,可以被复用。
  • 2,ExecutorService newFixedThreadPool(int threadNum):创建一个可重用的,具有固定线程数量的线程池。
  • 3,ExecutorService newSingleThreadExecutor():创建一个只有单线程的线程池,它相 于调用 newFixedThreadPool()方法时传入参数为1

测试用例:newFixedThreadPool、ewSingleThreadExecutor

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @ClassName ExecutorsFixedThreadPool
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/27.
*/
public class ExecutorsFixedThreadPool {
public static void main(String[] args) {
Runnable runnable = () -> {
String tName = Thread.currentThread().getName();
System.out.println(tName + "开始运行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tName + "\033[31;1m运行结束\033[0m");
};
// ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); //固定线程数量的线程池
ExecutorService fixedThreadPool = Executors.newSingleThreadExecutor(); //只有一个线程的线程池
for (int i=0; i<10; i++){
fixedThreadPool.submit(runnable,"te");
}
fixedThreadPool.shutdown(); }
}

3,线程池延迟任务和定时任务ScheduledExecutorService类

  • 1,newScheduledThreadPool(int corePooISize): 创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务 corePoolSize 指池中所保存的线程数,即使线程是空闲的也被保存在线程池
    执行任务方法:
    等待指定时间后执行一次:schedule(r,5, TimeUnit.SECONDS) ,r为Runnable或Callable对象后面   :
    等待指定时间后执行,然后周期性执行
    scheduleAtFixedRate(r,5,1,TimeUnit.SECONDS)
  • 2,newSingleThreadScheduledExecutor(): 创建只一个线程的线程池,它可以在指定延迟后执行线程任务
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; /**
* @ClassName ExecutorsScheduledThreadPoolTest
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/27.
*/
public class ExecutorsScheduledThreadPoolTest {
public static void main(String[] args) {
Runnable r = () -> {
String tName = Thread.currentThread().getName();
System.out.println(tName + "运行中");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tName + "运行结束");
};
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
/**
* schedule 任务已提交到线程池,5S后执行
*/
// executorService.schedule(r,5, TimeUnit.SECONDS); //任务已提交到线程池,5S后执行
/**
* scheduleAtFixedRate
* 任务等到时间才提交,周期性提交、不能shutdown,shutdown后无法提交了
* 注:如果下一次执行时,上次自行的还没结束,则这次取消执行
*/
executorService.scheduleAtFixedRate(r,5,1,TimeUnit.SECONDS);
// executorService.shutdown();
}
}

4,给定并行级别:

  • 1,ExecutorService newWorkStealingPool(int parallelism): 创建持有足够的线程的线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争
  • 2,ExecutorService newWorkStealingPool(): 该方法是前面方法的简化版本 如果前机器有4个CPU,则目标并行级别被设置为4
  • 这两个方法是Java8新增的,这两个方法可充分利用多 CPU 并行的能力 这两个方法生成的 work stealing 池,都相于后台线程池,如果所有的前台线程都死亡了workstealing 池中的线程会自动死亡。
这两个方法是Java8新增的,这两个方法可充分利用多 CPU 并行的能力 这两个方法生成的 work stealing 池,都相于后台线程池,如果所有的前台线程都死亡了workstealing 池中的线程会自动死亡。
 
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @ClassName ExecutorsWorkStealingPoolTest
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/27.
*/
public class ExecutorsWorkStealingPoolTest {
public static void main(String[] args) throws InterruptedException {
Runnable r = () -> {
String tName = Thread.currentThread().getName();
try {
System.out.println(tName + "开始运行");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tName + "运行结束");
};
/**
* 创建支持多核CPU并行的线程池
*/
ExecutorService executorService = Executors.newWorkStealingPool(); //译文:Stealing 窃取
for (int i=0; i<10; i++){
executorService.submit(r);
}
System.out.println(Runtime.getRuntime().availableProcessors()); //CPU核心数
Thread.sleep(3000);
}
}

 

java 多线程:线程池的使用Executors~ExecutorService; newCachedThreadPool;newFixedThreadPool(int threadNum);ScheduledExecutorService的更多相关文章

  1. java多线程----线程池源码分析

    http://www.cnblogs.com/skywang12345/p/3509954.html 线程池示例 在分析线程池之前,先看一个简单的线程池示例. 1 import java.util.c ...

  2. 深入理解Java多线程——线程池

    目录 为什么需要线程池 定义 ThreadPoolExecutor 工作队列workQueue 不同的线程池 Executor 线程池的工作原理 线程池生命周期 线程池增长策略 线程池大小的设置 线程 ...

  3. 跟我学Java多线程——线程池与堵塞队列

    前言 上一篇文章中我们将ThreadPoolExecutor进行了深入的学习和介绍,实际上我们在项目中应用的时候非常少有直接应用ThreadPoolExecutor来创建线程池的.在jdk的api中有 ...

  4. java 多线程 线程池:多核CPU利用ExecutorService newWorkStealingPool; ForkJoinPool线程池 执行可拆分的任务RecursiveAction;RecursiveTask

    1,给定并行级别: 1,ExecutorService newWorkStealingPool(int parallelism): 创建持有足够的线程的线程池来支持给定的并行级别,该方法还会使用多个队 ...

  5. java多线程--线程池的使用

    程序启动一个新线程的成本是很高的,因为涉及到要和操作系统进行交互,而使用线程池可以很好的提高性能,尤其是程序中当需要创建大量生存期很短的线程时,应该优先考虑使用线程池. 线程池的每一个线程执行完毕后, ...

  6. Java多线程——线程池

    系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互.在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池类似 ...

  7. java多线程——线程池源码分析(一)

    本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...

  8. [Java多线程]-线程池的基本使用和部分源码解析(创建,执行原理)

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 多线 ...

  9. Java多线程-----线程池详解

    1. 线程池的实现原理 提交一个任务到线程池中,线程池的处理流程如下: 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务.如果 ...

随机推荐

  1. 寒武纪加速平台(MLU200系列) 摸鱼指南(四)--- 边缘端实例程序分析

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  2. [Bzoj 1192][HNOI2006]鬼谷子的钱袋(二进制优化多重背包)

    (人生第一篇bzoj题解有点激动 首先介绍一下题目: 看它题目那么长,其实意思就是给定一个数a,求将其拆分成n个数,通过这n个数可以表示出1~a中所有数的方案中,求最小的n. 您看懂了嘛?不懂咱来举个 ...

  3. SP20173 DIVCNT2 - Counting Divisors (square)

    Refer 主要思路参考了 Command_block 的题解. Description 给定 \(n\)(\(n\le 10^{10}\)),求 \[\sum_{i=1}^n\sigma_0(i^2 ...

  4. 除了GO基因本体论,还有PO、TO、CO等各种Ontology?

    目录 PO/TO CO 后记 我们最常用最熟悉的功能数据库之一:GO(gene onotology),基因本体论.其实是一套标准词汇术语,目的是从不同角度来描述某个基因的特点和功能,三大本体如生物学进 ...

  5. C++类虚函数内存分布(这个 你必须懂)

    转自:http://www.cnblogs.com/jerry19880126/p/3616999.html C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来 ...

  6. C#集合Dictionary中按值的排序

    C#集合Dictionary中按值的降序排列 static void Main(string[] args) {             Dictionary<string, int> d ...

  7. linux系统中安装MySQL

    linux系统中安装MySQL 检查原来linux系统中安装的版本 rpm -qa | grep mysql 将其卸载掉 以 mysql-libs-5.1.71-1.el6.x86_64 版本为例 r ...

  8. Erda 1.1 版本发布|3 大亮点特性最新解读

    来源|尔达 Erda 公众号 ​ Erda v1.1 Changelog: https://github.com/erda-project/erda/blob/master/CHANGELOG/CHA ...

  9. 为什么CTR预估使用AUC来评估模型?

    ctr预估简单的解释就是预测用户的点击item的概率.为什么一个回归的问题需要使用分类的方法来评估,这真是一个好问题,尝试从下面几个关键问题去回答. 1.ctr预估是特殊的回归问题 ctr预估的目标函 ...

  10. Spring Cloud声明式调用Feign负载均衡FeignClient详解

    为了深入理解Feign,下面将从源码的角度来讲解Feign.首先来看看FeignClient注解@FeignClient的源码,代码如下: FeignClient注解被@Target(ElementT ...