对于服务端的应用而言,经常会出现比如定时任务,或者任务的异步执行,熟悉Java开发的开发者,经常会使用Executors类,其提供了4种不同的线程池: ​newCachedThreadPool, newFixedThreadPool, newScheduledThreadPool, newSingleThreadExecutor 这些线程池为我们在异步任务的执行等多线程的编程下提供了非常大的便利。

试想一下,每个任务都创建一个线程,这是非常不合理的,如果同时有大量的应用执行任务,那么我们的系统估计将会出现故障。通过过多的线程,在进行线程的上下文切换的过程中也是增加了系统的负载,而线程的创建,切换以及销毁都是需要消耗系统的资源的。

基于此,线程池技术应运而生,所谓的线程池技术就是在系统中存在一定数量的预先创建好的线程,这些线程接收保存在集合中的任务,从任务列表中获取任务去执行。执行完成之后,等待任务池中添加新的任务,然后取出,继续执行,如此往复。线程池技术一方面减少了线程池的创建,维护的成本,另一方面也在一定程度上缓解了大量任务导致线程被大量创建的问题。

1、线程池的定义

一般的线程池均有以下的定义(基于演示我们这里不做过多的功能,比如Java提供的线程设置任务池的大小,丢弃策略等等,这些并不是本文的重点,后面会在本栏目的其他文章中专门讲解线程池的实现以及应用)客户端通过将任务添加到任务池中就立即返回,不在等待任务的执行完成,提交任务完成后,其他工作线程接收到有新的任务的通知,会自动的获取任务并执行。

public interface ThreadPool {// 添加任务到任务池中void execute(T t);// 关闭线程池void shutdown();// 获取等待执行的任务数目int getCount();}

2、简单实现线程池

首先先定义一个抽象的任务类,抽象的任务类,有run方法,用于任务的执行。

public abstract class Job {/** 执行Job任务 */public abstract void handle();/** 返回任务的编号 */public abstract String number();}// 定义的睡眠任务public class SleepJob extends Job {private final int number;SleepJob(int number) {this.number = number;}@Overridepublic void handle() {try {TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));} catch (InterruptedException e) {Thread.currentThread().interrupt();}}@Overridepublic String number() {return String.valueOf(this.number);}}

Worker实现了Runable接口,是线程池中的工作者,用于执行线程池中的任务jobs

// 工作线程,负责消费任务public class Worker implements Runnable {private final DefaultThreadPool pool;private boolean running;public Worker(DefaultThreadPool pool) {this.pool = pool;this.running = true;}@Overridepublic void run() {while (running) {// 从连接池中获取任务,如果获取到了任务,就执行Job job = pool.getJob();if (job != null) {job.handle();System.out.println("任务:" + job.number() + "执行完成");}}}// 关闭该工作线程public void shutdown() {running = false;System.out.println("线程:" + Thread.currentThread().getName() + " 关闭");}

实现线程池的代码, init()方法中初始化若干个Worker,以Worker为基础创建线程并启动,Worker启动后,调用线程池的getJob方法用户获取任务。由于此时没有任务,线程均会执行wait() 工作线程进入WAIT状态,当调用线程池的增加任务时候,线程池执行​jobs.notify() 方法,通知并幻想处在WAIT状态的一个线程去获取Job并执行。

import java.util.LinkedList;public class DefaultThreadPool implements ThreadPool {// 工作队列final LinkedList jobs = new LinkedList<>();// 工作线程LinkedList workers = new LinkedList<>();// 初始化任务public void init(int initSize) {if (initSize < 0) {throw new RuntimeException("xxx");}for (int i = 0; i < initSize; i++) {// 构建Worker并启动线程,worker会等待任务池jobs中添加任务Worker worker = new Worker(this);workers.addLast(worker);Thread workThread = new Thread(worker, "ThreadPool-" + i);workThread.start();}}@Overridepublic void shutdown() {this.workers.forEach(Worker::shutdown);}@Overridepublic int getCount() {return this.jobs.size();}// 获取一个任务public Job getJob() {synchronized (jobs) {while (jobs.isEmpty()) {try {jobs.wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();return null;}}return jobs.removeFirst();}}// 添加任务@Overridepublic void execute(Job job) {if (job == null) {return;}// 添加任务,并发出通知唤醒一个线程,任务池有任务,getJob()方法获取到任务并返回synchronized (jobs) {jobs.addLast(job);jobs.notify();}}}

添加一个Job之后调用 ​jobs.notify() 方法通知一个线程去执行,这里不是调用 ​jobs.notifyAll() 是为了防止多个线程一起进入同步阻塞队列中。

3、线程池的使用

线程池创建完成之后,使用线程池就很简单了,下面的任务是创建5个工作线程,初始化100个任务交给这5个工作线程执行。

public static void main(String[] args) {// 初始化线程池DefaultThreadPool pool = new DefaultThreadPool();pool.init(5);System.out.println("ThreadPoolDemo.main start");// 添加100个任务,等待线程池中的工作线程去执行for (int i = 0; i < 100; i++) {pool.execute(new SleepJob(i));}}

这个测试案例相对而言比较简单,下面的一篇文章将会实现 基于线程池的简单的Web服务器 ,敬请关注!!!

4、 总结

可以看到,线程池的本质就是使用线程安全的工作队列连接工作线程以及客户端,客户端将任务放置到线程池中返回,工作线程从工作队列中取出任务,执行之。当工作队列为空的时候,全部的工作对垒均处于等待状态(WAITING),当客户端提交工作任务之后,将会通知任意一个线程启动去获取并执行任务。随着大量的任务被添加到工作队列,会有更多的工作线程被唤醒。

java 任务池_多线程的应用-异步任务线程池的简单实现相关推荐

  1. JAVA入门_多线程_邮局派发信件

    JAVA入门_多线程_邮局派发信件 Postman package cn.campsg.java.experiment.entity;public class Postman {private Str ...

  2. Java多线程学习(八)线程池与Executor 框架

    历史优质文章推荐: Java并发编程指南专栏 分布式系统的经典基础理论 可能是最漂亮的Spring事务管理详解 面试中关于Java虚拟机(jvm)的问题看这篇就够了 目录: [TOC] 本节思维导图: ...

  3. android 多线程下载,断点续传,线程池

    android 多线程下载,断点续传,线程池 你可以在这里看到这个demo的源码: https://github.com/onlynight/MultiThreadDownloader 效果图 这张效 ...

  4. Springboot异步任务线程池

    文章目录 1. 启动类添加@EnableAsync注解 2. 异步方法添加@Async注解 3. 自定义线程池以及线程池异常策略 1. 启动类添加@EnableAsync注解 package com. ...

  5. JDK 伪异步编程(线程池)

    伪异步IO编程 BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端链路,一个线程只能处理一个客户端连接.在高性能服务器应用领域,往往需要面向成千上万个客户 ...

  6. python线程池原理_Django异步任务线程池实现原理

    这篇文章主要介绍了Django异步任务线程池实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 当数据库数据量很大时(百万级),许多批量数据修改 ...

  7. [并发并行]_[线程池]_[Programming With POSIX Threads的线程池实现分析1]

    场景 1.C++标准库没有提供线程池操作, 连Win32都没有集成线程池, 相比之下macOS完善多了, 至少有operations. 多线程在执行多任务时有很大优势, 比如同时管理多个设备, 多个s ...

  8. java 多线程 张孝祥_多线程11_张孝祥 java5的线程锁技术

    本例子因为两个线程公用同线程中,使用同一个对象,实现了他们公用一把锁,实现了同一个方法的互斥. package locks; /** *会被打乱的效果 */ public class LockTest ...

  9. java线程 cpu占用率_多线程程序 怎样查看每个线程的cpu占用

    可以用下面的命令将 cpu 占用率高的线程找出来: ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu 这个命令首先指定参数'H',显示线程相关的 ...

最新文章

  1. 使用过滤器(Filter)解决请求参数中文乱码问题(复杂方式)
  2. ASP.NET MVC 3拥抱动态类型,徐汇区网站设计
  3. SpringMvc-Httl-shiro的整合
  4. Java的多线程和线程池的使用,你真的清楚了吗?
  5. 又到了上云时刻啦!!!阿里云 Docker部署SpringBoot项目 方便测试的部署方式
  6. 【转】你没有变强是因为你一直很舒服
  7. android 图片预览动画,Android图片上传实现预览效果
  8. Spring Boot使用AOP在控制台打印请求、响应信息
  9. 绝大部分投资者没资格谈心态
  10. Codeforces Round #339 (Div. 1) C. Necklace 构造题
  11. Padavan完整编译教程
  12. php msn,利用php给MSN发送消息
  13. libtorrent源码分析(二)VS上libtorrent编译总结
  14. 正则表达式校验手机号
  15. Photoshop实用的快捷键大全
  16. win10修复计算机摁什么,win10修复引导的方法教程
  17. 泡泡堂、QQ堂游戏通信架构分析
  18. mysql_dc.ncf_my live PC / ThinkCentre M920x Tiny / ThinkStation P330 Tiny
  19. 公众号二维码怎么生成
  20. 【OSPF外部路由-4类LSA(sum-asbr)和5类LSA(external)以及7类LSA(Nssa)】(OSPF的特殊区域)(外部路由选路特性)

热门文章

  1. linux变量循环赋值,shell脚本 循环变量赋值cf当前页面
  2. python之元组操作
  3. ubuntu20.10下mysql8数据库的安装(亲测)
  4. python资产管理系统_Python [5] IT资产管理(上)
  5. c语言学习-判断一个数的正、负,输出相应信息
  6. 为什么老是把词语读反_关于语言表达 6岁儿童经常把词语顺序念反
  7. MicroShift - 一个超轻量级 OpenShift 环境
  8. 在Typescript中使用ASP.NET Core SignalR和React创建实时应用程序
  9. Emulator 29.2.12 稳定版发布,启用 Google Maps UI
  10. JavaScript 九种跨域方式实现原理 1