Java 线程池的原理及实现
1、线程池简介:
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
线程池实现代码:
package com.wb.thread; import java.util.LinkedList;
import java.util.List; /**
* 线程池类
* @author wangbo
*
*/
public class ThreadPool { private static int worker_num = 5;//线程池中线程的个数,默认为5 private WorkThread[] workthreads;//工作线程 private static volatile int finished_task = 0;//未处理的任务 private List<Runnable> taskQueue = new LinkedList<Runnable>();//任务队列 private static ThreadPool threadPool; /**
* 无参构造器,创建线程池
*/
private ThreadPool(){
this(5);
} /**
* 含参构造器,创建线程池
* @param num
*/
private ThreadPool(int num){
worker_num = num;
workthreads = new WorkThread[num];
for (int i = 0; i < workthreads.length; i++) {
workthreads[i] = new WorkThread();
workthreads[i].start();//开启线程
}
} /**
* 获得一个默认线程个数的线程池
* @return
*/
public static ThreadPool getThreadPool(){
return getThreadPool(ThreadPool.worker_num);
} /**
* 获得一个指定线程个数的线程池
* @param num
* @return
*/
public static ThreadPool getThreadPool(int num) {
if (num <= 0) {
num = ThreadPool.worker_num;
}
if (threadPool == null) {
threadPool = new ThreadPool(num);
}
return threadPool;
} /**
* 将任务单个添加到队列
* @param task
*/
public void execute(Runnable task){
synchronized (taskQueue) {
taskQueue.add(task);
taskQueue.notify();
}
} /**
* 将任务批量添加到队列
* @param tasks
*/
public void execute(Runnable[] tasks){
synchronized (taskQueue) {
for (Runnable runnable : tasks) {
taskQueue.add(runnable);
}
taskQueue.notify();
}
} /**
* 将任务批量添加到队列
* @param tasks
*/
public void execute(List<Runnable> tasks){
synchronized (taskQueue) {
for (Runnable runnable : tasks) {
taskQueue.add(runnable);
}
taskQueue.notify();
}
} /**
* 销毁线程池
*/
public void destroy(){
//还有任务没有执行完
while(!taskQueue.isEmpty()){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//停止工作线程,且置为null
for (int i = 0; i < workthreads.length; i++) {
workthreads[i].stopWorker();
workthreads[i] = null;
}
threadPool = null;
taskQueue.clear();//清空队列
} /**
* 获取工作线程的个数
* @return
*/
public int getWorkThreadNumber(){
return worker_num;
} /**
* 获取已完成任务数量
* @return
*/
public int getFinishedTaskNumber(){
return finished_task;
} /**
* 获取未完成任务数量
* @return
*/
public int getWaitTaskNumber(){
return taskQueue.size();
} /**
* 获取线程池信息
*/
@Override
public String toString() {
return "工作线程数量:" + getWorkThreadNumber()
+ ",已完成任务数量" + getFinishedTaskNumber()
+ ",未完成任务数量" + getWaitTaskNumber(); } /**
* 内部类,工作线程
* @author wangbo
*
*/
private class WorkThread extends Thread{ private boolean isRunning = true;//线程有效标志 @Override
public void run() {
Runnable runnable = null;
while (isRunning) {
synchronized (taskQueue) {
//队列为空
while (isRunning && taskQueue.isEmpty()) {
try {
taskQueue.wait(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//队列不为空
if (!taskQueue.isEmpty()) {
runnable = taskQueue.remove(0);//去除任务
}
}
if (runnable != null) {
runnable.run();//执行任务
}
finished_task++;
runnable = null;
} } /**
* 停止线程
*/
public void stopWorker() {
isRunning = false;
} } }
测试代码:
package com.wb.thread; public class ThreadPoolTest { public static void main(String[] args) {
// 创建3个线程的线程池
ThreadPool t = ThreadPool.getThreadPool(3);
t.execute(new Runnable[] { new Task(), new Task(), new Task() });
t.execute(new Runnable[] { new Task(), new Task(), new Task() });
System.out.println(t);
t.destroy();//所有线程都执行完成才destory
System.out.println(t);
} // 任务类
static class Task implements Runnable { private static volatile int i = 1; @Override
public void run() {// 执行任务
System.out.println("任务 " + (i++) + " 完成");
}
} }
2、java类库中提供的线程池简介:
java.util.concurrent包提供了现成的线程池的实现。
示例代码:
package com.wb.thread; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* newCachedThreadPool()
* 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
* 有任务才会创建线程,空闲线程会被保留60s
* @author wangbo
*
*/
public class ThreadPoolExecutorTest1 { public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(index);
System.out.println(Thread.currentThread().getName());
}
});
}
} }
package com.wb.thread; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* newFixedThreadPool(int nThreads)
* 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
* 线程池中包含固定数目的线程,空闲线程会一直保留,参数nThreads表示设定线程池中线程的数目
* @author wangbo
*
*/
public class ThreadPoolExecutorTest2 { public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
System.out.println(Thread.currentThread().getName());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
} }
package com.wb.thread; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* newScheduledThreadPool(int corePoolSize)
* 线程池能按时间计划来执行任务,允许用户设定计划执行任务的时间。
* 参数corePoolSize设定线程池中线程最小数目,当任务较多时,线程池可能会创建更多的工作线程来执行任务。
* @author wangbo
*
*/
public class ThreadPoolExecutorTest3 { public static void main(String[] args) { method1();
method2(); } /**
* 延迟3s执行
*/
private static void method1(){
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("延迟2s执行");
}
}, 2, TimeUnit.SECONDS);
} /**
* 延迟2s执行后每3s执行一次
*/
private static void method2() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("延迟2s执行后每3s执行一次");
System.out.println(Thread.currentThread().getName());
}
}, 2, 3, TimeUnit.SECONDS);
} }
package com.wb.thread; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* newSingleThreadExecutor(int nThreads)
* 线程池中只有一个线程,它依次执行每个任务。
* 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
* @author wangbo
*
*/
public class ThreadPoolExecutorTest4 { public static void main(String[] args) {
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
System.out.println(Thread.currentThread().getName());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
} }
package com.wb.thread; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* newSingleThreadScheduledExecutor()
* 线程池中只有一个线程,它能按照时间计划执行每个任务。
* @author wangbo
*
*/
public class ThreadPoolExecutorTest5 { public static void main(String[] args) { method1();
method2(); } /**
* 延迟3s执行
*/
private static void method1(){
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("延迟2s执行");
}
}, 2, TimeUnit.SECONDS);
} /**
* 延迟2s执行后每3s执行一次
*/
private static void method2() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("延迟2s执行后每3s执行一次");
System.out.println(Thread.currentThread().getName());
}
}, 2, 3, TimeUnit.SECONDS);
} }
Java 线程池的原理及实现的更多相关文章
- Java线程池的原理及几类线程池的介绍
刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
- Java 线程池的原理与实现 (转)
最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. [分享]Java 线程池的原理与实现 这几天主要是狂看源程序,在弥补了一些以前知 ...
- Java线程池实现原理及其在美团业务中的实践
本文转载自Java线程池实现原理及其在美团业务中的实践 导语 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供 ...
- 我眼中的java线程池实现原理
最近在看java线程池实现方面的源码,在此做个小结,因为网上关于线程池源码分析的博客挺多的,我也不打算重复造轮子啦,仅仅用纯语言描述的方式做做总结啦! 个人认为要想理解清楚java线程池实现原理,明白 ...
- Java 线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java 线程池(ThreadPoolExecutor)原理解析
在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...
- Java线程池实现原理与技术(ThreadPoolExecutor、Executors)
本文将通过实现一个简易的线程池理解线程池的原理,以及介绍JDK中自带的线程池ThreadPoolExecutor和Executor框架. 1.无限制线程的缺陷 多线程的软件设计方法确实可以最大限度地发 ...
- 深入浅出JAVA线程池使用原理1
前言: Java中的线程池是并发框架中运用最多的,几乎所有需要异步或并发执行任务的程序都可以使用线程池,线程池主要有三个好处: 1.降低资源消耗:可以重复使用已经创建的线程降低线程创建和销毁带来的消耗 ...
- Java线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
随机推荐
- Unable to resolve target 'android-XX' 类似的错误。
解决办法: 打开项目代码中的Project target,将 复制代码 代码如下: # Project target. target=android-7 修改为你当前支持的ADK版本即可. 参考: ...
- bottle源码
import sys __author__ = 'Marcel Hellkamp' __version__ = '0.13-dev' __license__ = 'MIT' ############# ...
- Springboot访问静态资源
转载 http://blog.csdn.net/catoop/article/details/50501706
- Javaweb拦截器
http://blog.csdn.net/reggergdsg/article/details/52962774
- 加密 解密 RSA & AES & DES
git: https://github.com/XHTeng/XHCryptorTools rsa RSA加解密中必须考虑到的密钥长度.明文长度和密文长度问题.明文长度需要小于密钥长度,而密文长度则等 ...
- 实验十一 团队作业7---团队项目设计完善&编码测试
团队软件项目设计完善: 任务1:根据OOD详细设计工作要点,修改完善团队项目系统设计说明书和详细设计说明. <软件设计方案说明书>:https://github.com/cy0325/Te ...
- 如何方便的在windows测试python程序
听说python的网页抓取模块很强大,我想试试看看能给我的网络优化工作带来什么大的帮助,于是跟随廖雪峰老师开始学习python(地址查看),因为我用的是window系统,这就给程序的测试带来了很多麻烦 ...
- js 对象与json的转化
1.将对象转换为JSON格式字符串 JSON.stringify(object) 2.将JSON字符串转换为对象 JSON.parse(jsonString);
- oracle创建新用户和用户表空间
.首先,创建(新)用户: create user username identified by password; username:新用户名的用户名 password: 新用户的密码 也可以不创建新 ...
- JavaScript基础视频教程总结(071-080章)
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...