对于服务端而言,经常面对的是客户端传入的短小任务,需要服务端快速处理并返回结果。如果服务端每次接受一个客户端请求都创建一个线程然后处理请求返回数据,这在请求客户端数量少的阶段看起来是一个不错的选择,但是面对成千上万的请求在某一时段同时到达服务器时,如果还是采用这种方式,那么将会创建数以万计的线程,暂且不讨论线程是否会达到操作系统上限,单单操作系统频繁的进行线程的上下文切换就是一个巨大的开销,无故的增加的系统的负载,而线程的创建和消亡都是需要耗费系统资源的,也无疑造成了资源的浪费。

  线程池技术就能很好的解决这个问题,它事先创建好了若干个处理请求任务的线程,线程的数量并不受请求客户端的控制,在这前提下使用固定或者较为固定数目的线程来完成请求任务的处理,消除了频繁创建和消亡线程的系统资源开销。

  

  下面定义一个简单的线程池接口 :

public interface ThreadPool<Task extends Runnable> {

    //执行一个Task,这个Task需要实现Runnable
void execute(Task task) ; //关闭线程池
void shutdown() ; //增加工作线程
void addWorker(int num ) ; //减少工作线程
void removeWorker(int num); //得到正在执行的任务数量
int getTaskSize() ; }

  客户端可以通过execute(Task)方法将Task提交入线程池执行,而客户端自身不用等待Task的执行完成。线程池还提供了增加/减小工作线程以及关闭线程池的方法,这里的工作线程就代表了一个重复执行Task的线程,而每个由客户端提交的Task都将进入到一个等待队列中等待工作线程处理。

  接下来是线程池接口的默认实现 :

public class DefaultThreadPool<Task extends Runnable> implements ThreadPool<Task> {

    //线程池最大限制数
private static final int MAX_WORKER_NUMBERS = 10;
//线程池默认的数量
private static final int DEFAULT_WORKER_NUMBERS= 5;
//线程池最小数量
private static final int MIN_WORKER_NUMBERS = 1 ;
//这是一个任务列表,将会向里面插入任务
private final LinkedList<Task> jobs = new LinkedList<Task>() ;
// 工作者列表
private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>()) ;
//工作者线程的数量
private int workerNum = DEFAULT_WORKER_NUMBERS ;
//线程编号生成
private AtomicLong threadNum = new AtomicLong() ; public DefaultThreadPool(){
initializeWorkers(DEFAULT_WORKER_NUMBERS);
}
public DefaultThreadPool(int initSize){
workerNum = initSize > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS :
initSize < MIN_WORKER_NUMBERS ?MIN_WORKER_NUMBERS : initSize ;
initializeWorkers(workerNum);
} private void initializeWorkers(int num){
for(int i = 0 ; i < num ; i++){
Worker worker = new Worker() ;
workers.add(worker) ;
Thread t = new Thread(worker, "ThreadPool-worker-"+threadNum.incrementAndGet()) ;
t.start();
}
} @Override
public void execute(Task task) {
if(task!=null){
synchronized(jobs){
jobs.addLast(task);
//通知
jobs.notify();
}
}
} @Override
public void shutdown() {
for(Worker worker : workers){
worker.shutdown();
}
} @Override
public void addWorker(int num) {
//这里是否应该选择workers为监视器锁
synchronized(workers){
//判断新增的数量是否超出线程池的内置规则
if(num+this.workerNum > MAX_WORKER_NUMBERS){
num = MAX_WORKER_NUMBERS - this.workerNum ;
}
initializeWorkers(num);
this.workerNum += num ;
}
} @Override
public void removeWorker(int num) {
synchronized(workers){
if(num >= this.workerNum){
throw new IllegalArgumentException("beyond workNum") ;
} for(int i = 0 ; i < num ; i++){
Worker worker = workers.get(i);
if(workers.remove(worker)){
worker.shutdown();
}
}
this.workerNum -=num ;
}
} @Override
public int getTaskSize() { return jobs.size();
} class Worker implements Runnable{
private volatile boolean running ;
@Override
public void run() {
while(running){ Task job = null ;
synchronized(jobs){
//如果任务列表是空的,那么就wait
if(jobs.isEmpty()){
try {
jobs.wait();
} catch (InterruptedException e) {
//感知到外部对WorderThread的中断操作。返回
Thread.currentThread().interrupt();
return ;
}
}
job = jobs.removeFirst() ;
} if(job!=null){
try {
job.run();
} catch (Exception e) {
//忽略job执行中的exception
}
}
}//while end
}//run end
public void shutdown(){
running = false ;
}
}
}

Java线程池技术以及实现的更多相关文章

  1. java线程池技术(二): 核心ThreadPoolExecutor介绍

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...

  2. java线程池技术

    1.线程池的实现原理?简介: 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  3. java线程池技术(一):ThreadFactory与BlockingQueue

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.ThreadFactory概述以及源码分析 ThreadFactory很简单,就是一个线程工厂也就是负责生产线程的,我们看下ThreadFact ...

  4. java线程池系列(1)-ThreadPoolExecutor实现原理

    前言 做java开发的,一般都避免不了要面对java线程池技术,像tomcat之类的容器天然就支持多线程. 即使是做偏后端技术,如处理一些消息,执行一些计算任务,也经常需要用到线程池技术. 鉴于线程池 ...

  5. Java基础-Java中的并法库之线程池技术

    Java基础-Java中的并法库之线程池技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是线程池技术 二.

  6. 池化技术之Java线程池

     https://blog.csdn.net/jcj_2012/article/details/84906657 作用 线程池,通过复用线程来提升性能; 背景 线程是一个操作系统概念.操作系统负责这个 ...

  7. 深度分析:Java并发编程之线程池技术,看完面试这个再也不慌了!

    线程池的好处 Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池,相对于单线程串行处理(Serial Processing ...

  8. Java 线程池的原理与实现

    最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. 建议:在阅读本文前,先理一理同步的知识,特别是syncronized同步关键字的用法.关 ...

  9. Java线程池的实现

    线程池的作用: 一个线程的周期分为:创建.运行.销毁三个阶段. 处理一个任务时,首先创建一个任务线程,然后执行任务,完了还要销毁线程.而线程只有处于运行状态的时候,才是真的在处理我们交给它的任务,这个 ...

随机推荐

  1. springboot 集成 freemarker

    前面我们已经实现了thymeleaf模板,其实freemarker和thymeleaf差不多,都可以取代JSP页面,实现步骤也差不多,我们来简单实现一下 引入pom.xml依赖如下 <depen ...

  2. [Android] 环境配置之Android Studio开发NDK

    分类:Android环境搭建 (14351)  (20) ========================================================作者:qiujuer博客:bl ...

  3. vue生命周期的栗子

    vue生命周期的栗子注意触发vue的created事件以后,this便指向vue实例,这点很重要 <!DOCTYPE html><html><head><me ...

  4. Git 的使用Git Bash和Git GUI

    使用Github也有一年的时间了,之前一直都是使用的Github客户端,对提交,更新,克隆,合并,分支有一定的了解和实践.一直都想试试命令行的形式,但是感觉可能桌面版的方便就没有做. 可是Github ...

  5. byte 单位换算

    1G就1GB啦,平时人们说1G只是简洁来说而已. bit(位).B(字节).K(千).M(兆).G(吉咖).T(太拉) B(Byte).KB(KiloByte).MB(MegaByte).GB(Gig ...

  6. C结构体之位域(位段)(转)

    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可.为了节省存储空间,并使处理简便,C语言又提供了一种数据结构 ...

  7. asp .net 为图片添加文字水印(内包含有加图片水印的方法) .

    在项目中先创建一个Imag_writer 类库 在该类库下分别创建两个枚举类型WaterMarkType (水印的类型).WaterMarkPosition (水印的位置).代码如下: using S ...

  8. Intel® RAID Software User’s Guide

    Intel® RAID Software User’s Guide: •Intel ® Embedded Server RAID Technology 2 •Intel ® IT/IR RAID •I ...

  9. PHP中使用Redis

    Redis是什么 Redis ( REmote DIctionary Server ) , 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用 ...

  10. YUV格式

    http://blog.csdn.net/u011270282/article/details/50696616 http://blog.csdn.net/acs713/article/details ...