使用多线程以及线程池的意义无需多说,要想掌握线程池,最好的方法还是自己手动去实现。

一、实现思路

                      (网络盗图)

二、实现代码

1、线程池类

package com.ty.thread;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; /**
* @author Taoyong
* @date 2018年5月17日
* 天下没有难敲的代码!
*/
public class ThreadPoolExecutor { /*
* BlockingQueue是阻塞队列,在两种情况下出现阻塞:
* 1、当队列满了,入队列操作时;
* 2、当队列空了,出队列操作时。
* 阻塞队列是线程安全的,主要使用在生产/消费者的场景
*/
private BlockingQueue<Task> blockingQueue; //线程池的工作线程数(可以认为是线程池的容量)
private int poolSize = 0; //线程池的核心容量(也就是当前线程池中真正存在的线程个数)
private int coreSize = 0; /*
* 此地方使用volatile关键字,volatile的工作原理是:对于JVM维度来说,每个线程持有变量的工作副本,那对于计算机维度来说,
* 就是这些变量的中间值会存放在高速缓存中。通过volatile关键字,告知每个线程改变此变量之后,立马更新到内存中去,并且使得
* 缓存中的数据失效,这样来保证其中某个线程改变公有变量后,其他线程能及时读取到最新的变量值,从而保证可见性。
* 原因如下:
* 1、在ThreadPoolExecutorTest中操作shutDown,这是main线程操作此变量(由于变量是volatile声明,所以会立马写入内存中);
* 2、Worker中线程通过while(!shutDown)来判断当前线程是否应该关闭,因此需通过volatile保证可见性,使线程可以及时得到关闭。
*/
private volatile boolean shutDown = false; public ThreadPoolExecutor(int size) {
this.poolSize = size;
//LinkedBlockingQueue的大小可以指定,不指定即为无边界的。
blockingQueue = new LinkedBlockingQueue<>(poolSize);
} public void execute(Task task) throws InterruptedException {
if(shutDown == true) {
return;
} if(coreSize < poolSize) {
/*
* BlockingQueue中的插入主要有offer(obj)以及put(obj)两个方法,其中put(obj)是阻塞方法,如果插入不能马上进行,
* 则操作阻塞;offer(obj)则是插入不能马上进行,返回true或false。
* 本例中的Task不允许丢失,所以采用put(obj);
*/
blockingQueue.put(task);
produceWorker(task);
}else {
blockingQueue.put(task);
}
} private void produceWorker(Task task) throws InterruptedException {
if(task == null) {
throw new NullPointerException("非法参数:传入的task对象为空!");
} Thread thread = new Thread(new Worker());
thread.start();
coreSize++;
} /*
* 真正中断线程的方法,是使用共享变量发出信号,告诉线程停止运行。
*
*/
public void shutDown() {
shutDown = true;
} /*
* 此内部类是实际上的工作线程
*
*/
class Worker implements Runnable { @Override
public void run() {
while(!shutDown) {
try {
//
blockingQueue.take().doJob();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程:" + Thread.currentThread().getName() + "退出运行!");
}
}
}

2、Task类(需要被线程处理的任务类)

package com.ty.thread;

/**
* @author Taoyong
* @date 2018年5月17日
* 天下没有难敲的代码!
*/
public class Task { //通过taskId对任务进行标识
private int taskId; public Task(int taskId) {
this.taskId = taskId;
} public void doJob() {
System.out.println("线程" + Thread.currentThread().getName() + "正在处理任务!");
} public int getId() {
return taskId;
}
}

3、测试类

package com.ty.thread;

/**
* @author Taoyong
* @date 2018年5月17日
* 天下没有难敲的代码!
*/
public class ThreadPoolExecutorTest { public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3);
for(int i = 0; i < 10; i++) {
Task task = new Task(i);
threadPoolExecutor.execute(task);
} threadPoolExecutor.shutDown();
}
}

4、运行结果

线程Thread-0正在处理任务!
线程Thread-1正在处理任务!
线程Thread-0正在处理任务!
线程Thread-1正在处理任务!
线程Thread-2正在处理任务!
线程Thread-0正在处理任务!
线程Thread-1正在处理任务!
线程:Thread-1退出运行!
线程:Thread-0退出运行!
线程Thread-2正在处理任务!
线程:Thread-2退出运行!

当第十个任务待处理时,整个线程池已经被shutDown,整个流程结束。

项目代码已经上传到github中:https://github.com/ali-mayun/threadPool

简单实现java线程池的更多相关文章

  1. 这么说吧,java线程池的实现原理其实很简单

    好处 : 线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配.调优和监控,有以下好处: 1.降低资源消耗: 2.提高响应速度: 3.提高线 ...

  2. java线程池ThreadPoolExecutor理解

    Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.newFixe ...

  3. Java线程池使用说明

    Java线程池使用说明 转自:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极 ...

  4. Java线程池的几种实现 及 常见问题讲解

    工作中,经常会涉及到线程.比如有些任务,经常会交与线程去异步执行.抑或服务端程序为每个请求单独建立一个线程处理任务.线程之外的,比如我们用的数据库连接.这些创建销毁或者打开关闭的操作,非常影响系统性能 ...

  5. Java线程池的原理及几类线程池的介绍

    刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...

  6. [转 ]-- Java线程池使用说明

    Java线程池使用说明 原文地址:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1. ...

  7. java线程池的使用与详解

    java线程池的使用与详解 [转载]本文转载自两篇博文:  1.Java并发编程:线程池的使用:http://www.cnblogs.com/dolphin0520/p/3932921.html   ...

  8. java线程池分析和应用

    比较 在前面的一些文章里,我们已经讨论了手工创建和管理线程.在实际应用中我们有的时候也会经常听到线程池这个概念.在这里,我们可以先针对手工创建管理线程和通过线程池来管理做一个比较.通常,我们如果手工创 ...

  9. Java线程池使用和分析(二) - execute()原理

    相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...

随机推荐

  1. Codeforces Beta Round #29 (Div. 2, Codeforces format)

    Codeforces Beta Round #29 (Div. 2, Codeforces format) http://codeforces.com/contest/29 A #include< ...

  2. PTA 7-7 六度空间(广搜)

    “六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论.这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够 ...

  3. Json、JavaBean、String等互转

    Json.JavaBean.String等互转 本文介绍简单的Json.JavaBean.String互换(下文JavaBean简称Object对象,这里不是很严谨) 转换关系如下: 其中String ...

  4. .NET通用工具——正则表达式

    正则表达式就是一组字符串运算规则,你需要先把元字符记熟,然后就可以随意组合获得你想要的结果.把一些常用的正则表达式背下来也是一种方法,再加以变化获得你想要的结果. 正则表达式不需要刻意的去学习,当用到 ...

  5. Repeater控件添加序号列

    在项目开发过程中,会经常遇到ASP.NET repeater控件添加序号列,有些新手可能还不会,网上搜集整理了一些,需要的朋友可以参考下 ASP.NET repeater添加序号列的方法 1.< ...

  6. Windows 获取unix timestamp

    #include <stdio.h> #include <time.h> int main(){ SYSTEMTIME lpSysTime; GetLocalTime(& ...

  7. JAVA软件安装

    Java配置----JDK开发环境搭建及环境变量配置 文章来源:http://www.cnblogs.com/smyhvae/p/3788534.html Tomcat安装.配置和部署笔记 文章来源: ...

  8. Python 列表推导实例

    #!/usr/bin/python # -*- coding: utf-8 -*- with open('e:/123.txt') as fp:row = fp.readlines() #打开并读取所 ...

  9. const修饰符用法

    1. 将一个对象设置为不可修改 const int a = 100; 2. 指向const对象的指针 const int* p = 3;可以通过指针来修改指针所指向的值,但是不能通过指针*p修改对像的 ...

  10. qrcodenet二维码图片下扩展区域添加号段的操作

    总监安排了个任务,一个号码导出一个二维码图, 我实现了最终还能批量生成,结果主管说要在图片下边添加一行,和图片是一起的 最开始把控件的上的图给改了,结果保存起来没用,控件上的图跟要保存的不是一个事. ...