线程池ThreadPool

线程池概念

线程频繁创建和关闭,比较耗费cpu性能,可以通过线程池来管理,类似数据库连接池一样的道理.
学习Java的线程池,必须先知道创建线程池的原始类和方法ThreadPoolExecutor

类继承关系
    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
  • corePoolSize:线程池核心线程数,空闲也不会被销毁

  • maximumPoolSize:线程池最大线程数

  • keepAliveTime:超出corePoolSize数量的线程的保留时间

  • unit:keepAliveTime单位

  • workQueue:阻塞队列,存放来不及执行的线程

    • ArrayBlockingQueue:构造函数一定要传大小
    • LinkedBlockingQueue:构造函数不传大小会默认为(Integer.MAX_VALUE ),当大量请求任务时,容易造成 内存耗尽。
    • SynchronousQueue:同步队列,一个没有存储空间的阻塞队列,将任务同步交付给工作线程。
    • PriorityBlockingQueue : 优先队列
  • threadFactory:线程工厂,一般默认即可

  • handler:饱和策略

    • AbortPolicy(默认):直接抛弃
    • CallerRunsPolicy:用调用者的线程执行任务
    • DiscardOldestPolicy:抛弃队列中最久的任务
    • DiscardPolicy:抛弃当前任务

常用线程池和方法

线程池:

  • newFixedThreadPool 固定线程池,可控制线程最大并发数,超出线程在队列中等待。
  • newSingleThreadExecutor 单线程池,用唯一的工作线程来执行任务。
  • newCachedThreadPool 缓存线程池,灵活回收空闲线程。
  • newScheduledThreadPool 定长线程池,支持定时及周期性任务执行。

方法:

  • execute() 添加任务
  • submit() 提交任务
  • shutdown() 关闭线程池
  • shutdownNow() 立即关闭线程池

1.测试线程类


public class MyThread implements Runnable { private String curName; public MyThread() {
} public MyThread(String curName) {
this.curName = curName;
} public String getCurName() {
return curName;
} public void setCurName(String curName) {
this.curName = curName;
} public void run() {
System.out.println("=========>>>开始执行:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
System.out.println(Thread.currentThread().getName()+": "+this.curName);
try {
Thread.sleep(2000);// 模拟线程执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

2.newFixedThreadPool固定线程池

初始化线程池大小为3,模拟10个线程并发场景

/**
* 测试:定长线程池
*/
public void fixedPool(){
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
}

 

3.newSingleThreadExecutor单线程池

按照顺序一个一个执行

/**
* 测试:单线程池
*/
public void singlePool(){
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
}

 

4.newCachedThreadPool缓存线程池

/**
* 测试:缓存线程池
*/
public void cachePool(){
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
}

 

5.newScheduledThreadPool定长线程池

线程池支持延时执行和周期执行

  • schedule(Callable callable, long delay, TimeUnit unit)延时执行
  • scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)延时固定间隔执行
  • scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)第一次执行完,延时固定间隔执行
/**
* 测试:定长线程池
*/
public void scheduledPool(){
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
System.out.println("=========>>>启动线程池:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
// 延时3秒执行
pool.schedule(new MyThread("线程01_延时"),3,TimeUnit.SECONDS);
// 延时5秒循环执行
pool.scheduleAtFixedRate(new MyThread("线程02_延时_循环"),5,5,TimeUnit.SECONDS);
pool.scheduleWithFixedDelay(new MyThread("线程03_延时_循环"),5,5,TimeUnit.SECONDS);
// 不关闭线程池
// pool.shutdown();
}

 

6.完整代码

package com.lyf.thread;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*; /**
* @author lyf
* @date 2019/8/11 11:03
*
* newFixedThreadPool 固定线程池,可控制线程最大并发数,超出线程在队列中等待。
* newSingleThreadExecutor 单线程池,用唯一的工作线程来执行任务。
* newCachedThreadPool 缓存线程池,灵活回收空闲线程。
* newScheduledThreadPool 定长线程池,支持定时及周期性任务执行。
* 常用方法:
* execute() 添加任务
* submit() 提交任务
* shutdown() 关闭线程池
* shutdownNow() 立即关闭线程池
*/ public class MyThread implements Runnable { private String curName; public MyThread() {
} public MyThread(String curName) {
this.curName = curName;
} public String getCurName() {
return curName;
} public void setCurName(String curName) {
this.curName = curName;
} public void run() {
System.out.println("=========>>>开始执行:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
System.out.println(Thread.currentThread().getName()+": "+this.curName);
try {
Thread.sleep(2000);// 模拟线程执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
} /**
* 测试:固定线程池
*/
public void fixedPool(){
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
} /**
* 测试:单线程池
*/
public void singlePool(){
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
} /**
* 测试:缓存线程池
*/
public void cachePool(){
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
} /**
* 测试:定长线程池
*/
public void scheduledPool(){
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
System.out.println("=========>>>启动线程池:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
// 延时3秒执行
pool.schedule(new MyThread("线程01_延时"),3,TimeUnit.SECONDS);
// 延时5秒循环执行
pool.scheduleAtFixedRate(new MyThread("线程02_延时_循环"),5,5,TimeUnit.SECONDS);
pool.scheduleWithFixedDelay(new MyThread("线程03_延时_循环"),5,5,TimeUnit.SECONDS);
// 不关闭线程池
// pool.shutdown();
} public static void main(String []args) {
MyThread myThread = new MyThread();
// myThread.fixedPool();
// myThread.singlePool();
// myThread.cachePool();
myThread.scheduledPool();
} }

submit和execute方法区别

submit和execute方法都可以提交任务到线程池中,区别3点:

  1. 接收参数不一样,submit需要线程实现Callable接口
  2. submit有返回值,而execute没有
  3. submit可以处理线程内部异常
package com.lyf.thread;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*; class MyThread02 implements Callable<String> { @Override
public String call() throws Exception {
// 模拟3s~10s之间的延时和返回结果
long time = (long) (Math.random()*7+3);
Thread.sleep(time*1000);
String curName = Thread.currentThread().getName();
System.out.println("=========>>>执行完毕:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
return curName+"_"+time;
} public static void main(String[] args) {
System.out.println("=========>>>启动线程池:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
ExecutorService executorService2 = Executors.newFixedThreadPool(5);// 定长线程池
List<Future<String>> futureList = new ArrayList<>();//存储任务
for (int i = 0; i < 5; i++) {
Future<String> future = executorService2.submit(new MyThread02());
futureList.add(future);
}
for (int i = 0; i < 5; i++) {
Future<String> future = futureList.get(i);
try {
System.out.println("Result: " + future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executorService2.shutdown();
}
}

线程池ThreadPool实战的更多相关文章

  1. 线程池ThreadPool的初探

    一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...

  2. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  3. 高效线程池(threadpool)的实现

    高效线程池(threadpool)的实现 Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线 ...

  4. 多线程系列 线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  5. Spring线程池开发实战

    Spring线程池开发实战 作者:chszs,转载需注明. 作者博客主页:http://blog.csdn.net/chszs 本文提供了三个Spring多线程开发的例子,由浅入深,由于例子一目了然, ...

  6. C# -- 使用线程池 ThreadPool 执行多线程任务

    C# -- 使用线程池 ThreadPool 执行多线程任务 1. 使用线程池 class Program { static void Main(string[] args) { WaitCallba ...

  7. 多线程Thread,线程池ThreadPool

    首先我们先增加一个公用方法DoSomethingLong(string name),这个方法下面的举例中都有可能用到 #region Private Method /// <summary> ...

  8. C# 线程池ThreadPool的用法简析

    https://blog.csdn.net/smooth_tailor/article/details/52460566 什么是线程池?为什么要用线程池?怎么用线程池? 1. 什么是线程池? .NET ...

  9. 多线程系列(2)线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

随机推荐

  1. 打印出js对象里面的内容

    最近调试的时候遇到需要打印出js对象里面的内容,两种方式: 1.直接使用 JSON.stringify(obj) 方法把对象转成字符串,打印出来.但是因为维护的项目比较老,使用的还是ie11的ie5兼 ...

  2. 在Visual Studio中直接编译Fluent的UDF

    VS版本:Visual Studio 2013 Fluent版本:Fluent18.2 首先我们启动VS Studio中直接编译Fluent的UDF" title="在Visual ...

  3. cpu指令重排序的原理

    目录: 1.重排序场景 2.追根溯源 3.缓存一致性协议 4.重排序原因 一.重排序场景 class ResortDemo { int a = 0; boolean flag = false; pub ...

  4. ThreadLocal是什么

    早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序. 当使 ...

  5. 基于Hive的对BiliBili用户信息进行数据分析

    用户表字段信息: 1.查出前1000位用户的用户名,关注数和粉丝数. 2.查询关注数大于100的用户的用户名和关注数. 3.查询粉丝数大于100的用户的用户名,粉丝数. 4.查询id为1000的用户的 ...

  6. IE安全限制

    在安全级别下面设置置进行如下调整: A.ActiveX控件自动提示:启用 B.对标记为可安全执行脚本的ActiveX控件执行脚本:启用 C.对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本 ...

  7. 关于jvm系统属性-Djava.awt.headless 模式

    1. 什么是 java.awt.headless? Headless模式是系统的一种配置模式.在系统可能缺少显示设备.键盘或鼠标这些外设的情况下可以使用该模式. 2. 何时使用和headless mo ...

  8. npm install Error: EACCES: permission denied, mkdir

    今天研究Electron的时候,全局安装运行 npm install electron -g时侯,报下面的错误: Error: EACCES: permission denied, mkdir '/U ...

  9. 从安装PHP到第一个tomcat执行的hello world其实没那么难

    001 初入门的朋友问我为什么她的PHP老是不能安装运行成功,作为一个乐(shi)于(li)助(liao)人(mei)的半程序员, 自然是要好好研究然后手把手教妹纸了! 002 话不多说,进入正题 为 ...

  10. python web开发——django学习(二)第一个django网站运行成功

    1.写message_form.html <!DOCTYPE html> <html lang="en"> <head> <meta ch ...