线程池

线程池就是一个线程的容器【可以是链表,数组等】。

作用

作用就是限制系统中执行线程的数量,可以自动或手动设置线程数量,以达到最佳效果【少了浪费系统资源,多了消耗资源(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)】。

假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。【T=T1+T2+T3】
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。

线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。

结构

线程池通常由这样几个概念(接口)组成:

1.线程池管理器(ThreadPool):用于创建线程池,销毁线程池,添加新任务;池是一个容器,容器中有很多个执行器,每一个执行器是一个线程。池必须提供一个可以从中取出执行器方法,可能还需要一个池中现有活动线程数方法,销毁池的方法等。

2. 工作线程(workthread):也叫执行器,每个执行器是一个线程,每个执行器可以执行一个任务,作为一个线程,他可以独立运行,执行器执行完自身后,需要将自身放入池中。

3.任务接口(Task ):每个任务必须实现的接口,以供工作线程调度任务的执行。

任务是每个线程具体要做的事,如资源下载,播放flash片段,打印一段文字到控制台等等,它本身不能执行,而需要将自身交给执行器。

4.任务队列:提供一种【缓冲机制】,用于存放没有处理的任务。

整个池的机制和结构就是这样,当然,需要一个调度者(scheduler)来协调主线程和池的关系。

接口的目的是为了让我们从细节中解脱出来,从一个比较抽象的层次来描述系统,这样的好处是简单,而且设计出来的框架比较通用,可以适应很多相近相似的情况。

工作原理(同步在线程的并发中意义非常之大,对临界资源的控制是并发时最关键的地方)

当一个新任务需要运行时:

如果线程池中有等待的工作线程【空闲线程】,可以立即开始运行

如果线程池中没有空闲线程时,新来的请求就必须等待。直到一个Task运行结束后,这个请求一方面将自己放入pool【线程池】中,一方面需要通知等待在pool中的其他线程。

【注意】每一个执行器线程,一开始启动,则进入等待状态,此时不会消耗CPU资源。而当在外部调用执行器的startTask()方法,即可通知线程从等待状态中醒来,取出Task并执行后,再将执行器本身放入池中,然后继续等待。

Java自带的线程池

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

比较重要的几个类:

ExecutorService 真正的线程池接口。
ScheduledExecutorService 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ThreadPoolExecutor ExecutorService的默认实现。
ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。

在Executors类里面提供了一些静态工厂,生成一些常用的线程池:

1.newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

2.newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

3. newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

4.newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

实例:

1.newSingleThreadExecutor(单个后台线程)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Mythread extends Thread{public void run(){System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {ExecutorService pool = Executors.newSingleThreadExecutor();//<span style="font-family: Helvetica, Tahoma, Arial, sans-serif;font-size:12px; line-height: 25.200000762939453px; text-indent: 28px;">创建一个单线程的线程池</span>Thread t1 = new Mythread();Thread t2 = new Mythread();pool.execute(t1);pool.execute(t2);pool.shutdown();//关闭线程池}
}

【运行结果】:

2.newFixedThreadPool(固定大小线程池)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Mythread extends Thread{public void run(){System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {ExecutorService pool = Executors.newFixedThreadPool(2);//创建一个可重用固定线程数的线程池//将线程放入到线程池中pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.shutdown();}
}

【可能的运行结果】:

3.newCachedThreadPool(无界线程池,可以进行自动线程回收)【建议使用】

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Mythread extends Thread{public void run(){System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {ExecutorService pool = Executors.newCachedThreadPool();//创建一个可缓存的线程池//将线程放入到线程池中pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.execute(new Thread(new Mythread()));pool.shutdown();}
}

【可能的运行结果】:

4.newScheduledThreadPool(定时周期执行,无限大小的线程池)

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class Mythread extends Thread {public void run() {System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {// 创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于TimerScheduledExecutorService timer = Executors.newScheduledThreadPool(1);// 将线程放入到线程池中timer.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("i'm adanac");}}, 1, 1, TimeUnit.SECONDS);timer.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {//设置日期格式SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//获取当前系统时间System.out.println(sdf.format(new Date()));}}, 500, 500, TimeUnit.MILLISECONDS);}
}

【运行结果:】


线程池的简单实现

池是一个容器,我们考虑使用java.util.LinkedList类(可能由于它的长度是可变的,而且不需要我们使用者来考虑),也就是说,池需要维护一个链表。

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;/*** @author AdanacLFZ** 线程池管理器* 功能:创建线程池,销毁线程池,添加新任务*/
class ThreadPoolManager {  private static ThreadPoolManager instance = null;  private List<Upload> taskQueue = Collections.synchronizedList(new LinkedList<Upload>());//任务队列  private WorkThread[] workQueue ;    //工作线程(真正执行任务的线程)  private static int worker_num = 5;    //工作线程数量(默认工作线程数量是5)  private ThreadPoolManager(){  this(5);  }  private ThreadPoolManager(int num){  worker_num = num;  workQueue = new WorkThread[worker_num];  for(int i=0;i<worker_num;i++){  workQueue[i] = new WorkThread(i);  }  }  public static synchronized ThreadPoolManager getInstance(){  if(instance==null)  instance = new ThreadPoolManager();  return instance;  }  public void addTask(Upload task){  //对任务队列的操作要上锁  synchronized (taskQueue) {  if(task!=null){  taskQueue.add(task);  taskQueue.notifyAll();  System.out.println(task.getInfo() + " submit!");  }  }  }  public void BatchAddTask(Upload[] tasks){  //对任务队列的修改操作要上锁  synchronized (taskQueue) {  for(Upload e:tasks){  if(e!=null){  taskQueue.add(e);  taskQueue.notifyAll();  System.out.println(e.getInfo() + " submit!");  }  }          }  }  public void destory(){  System.out.println("pool begins to destory ...");  for(int i = 0;i<worker_num;i++){  workQueue[i].stopThread();  workQueue[i] = null;  }  //对任务队列的操作要上锁  synchronized (taskQueue) {  taskQueue.clear();  }  System.out.println("pool ends to destory ...");  }  private class WorkThread extends Thread{  private int taksId ;  private boolean isRuning = true;  private boolean isWaiting = false;  public WorkThread(int taskId){  this.taksId= taskId;  this.start();  }  public boolean isWaiting(){  return isWaiting;  }  // 如果任务进行中时,不能立刻终止线程,需要等待任务完成之后检测到isRuning为false的时候,退出run()方法  public void stopThread(){  isRuning = false;  }  @Override public void run() {  while(isRuning){  Upload temp = null;  //对任务队列的操作要上锁  synchronized (taskQueue) {  //任务队列为空,等待新的任务加入  while(isRuning&&taskQueue.isEmpty()){  try {  taskQueue.wait(20);  } catch (InterruptedException e) {  System.out.println("InterruptedException occre...");  e.printStackTrace();  }  }  if(isRuning)  temp = taskQueue.remove(0);  }  //当等待新任务加入时候,终止线程(调用stopThread函数)造成 temp = null  if(temp!=null){  System.out.println("task info: "+temp.getInfo()+ " is begining");  isWaiting = false;  temp.uploadPic();  isWaiting = true;  System.out.println("task info: "+temp.getInfo()+ " is finished");  }      }  }  }
} abstract class Upload {  protected String info;  abstract boolean uploadPic();  public String getInfo(){  return info;  }
}class TaskUpload extends Upload {  public TaskUpload(String info){  this.info = info;  }  public String getInfo(){  return info;  }  @Override public boolean uploadPic()  {  // TODO Auto-generated method stub  System.out.println(info+" sleep begin ....");  try {  Thread.sleep(2000);  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  System.out.println(info+" sleep end ....");  return false;  }
} public class ThreadPoolManagerTest {  public static void main(String[] args) {  Upload[] tasks = createBatchTask(7);  ThreadPoolManager pool = ThreadPoolManager.getInstance();  pool.BatchAddTask(tasks);  pool.destory();  }  private static Upload[] createBatchTask(int n){  Upload[] tasks = new TaskUpload[n];  for(int i = 0;i<n ;i++ ){  tasks[i] = new TaskUpload("task_"+ i);  }  return tasks;  }
} 

【可能的运行结果】:(运行不大正确)

黑马程序员_Java_线程池相关推荐

  1. 黑马程序员_Java_交通灯管理

    交通灯管理项目模拟了对十字路口交通灯的控制,一般在我们生活中的十字路口是有人行道的,而此项目没有考虑人行道,到下面需求的第3条,右转车辆不受信号灯控制可以看出. 具体的需求如下: 1.异步随机生成按照 ...

  2. 黑马程序员_Java_多线程

    线程的理解 1.同一个应用中,多个任务同时进行.就像editplus编辑工具,打开一个文件窗口就是一个线程. 2.线程可以有多个,但cpu每时每刻只做一件事(多核除外).由于cpu处理速度很快,我们就 ...

  3. 黑马程序员-day10-多线程上部分

    ------- <a href="http://www.itheima.com" target="blank">android培训</a> ...

  4. 黑马程序员-String常量池

    ---------------------- ASP.Net+Android+IOS开发..Net培训.期待与您交流! ---------------------- 理解Java常量池 JVM运行时数 ...

  5. 黑马程序员————java线程之间的通信

    ------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS ...

  6. 黑马程序员_Java_反射

    反射 Reflection,听其名就像照镜子一样,既能看见自己也可以看见别人的每一部分.反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作.例如 ...

  7. 黑马程序员_Java_异常

    /* 异常:就是程序在运行时出现的不正常情况,其实就是java对不正常情况进行描述后的对象体现,通过java的类的形式进行描述,并封装成对象.两种划分:1.严重的问题:Java通过Error类进行描述 ...

  8. 黑马程序员_java_银行售票系统

    ------- android培训.java培训.期待与您交流! ---------- 银行业务调度系统 6个窗口 1-4  普通窗口 5 快速窗口(交费用的) 6 vip窗口 客户随机生成 1:6: ...

  9. 黑马程序员入学Java知识——精华总结

    黑马程序员入学Java知识--精华总结 J2SE部分,Java高新技术部分,7K面试题部分等黑马入学要求的知识点总结! 一.黑马程序员-java概述与基础知识 6 1.何为编程? 6 2.Java语言 ...

最新文章

  1. 2020中国大学本科毕业生质量排行榜公布(附前152名)
  2. QT利用QCustomplot绘制折线图海底声速梯度图,解决一条曲线中一个X值对应两个Y值
  3. ORACLE表空间的相关操作
  4. 第三章 正态性检验、自相关检验与异方差性检验
  5. java war 反编译_war反编译成java项目
  6. 一些可能有用的功能cocos2dx
  7. 微星X79主板修改BIOS支持NVMe
  8. eclipse svn忽略指定文件或文件夹
  9. vue.js转换乘html_Vue.js的声明式共享元素转换
  10. Debian 6(Squeeze)升级至Debian 7(Wheezy)
  11. 软件质量的定义以及相关理论
  12. 网络层HTPPS和HTTP的概念与区别
  13. matlab中三视图如何画,[matlab 三维图]怎样把三维图导入到MATLAB
  14. (翻译)表单中应使用文本域输入地址的原因
  15. Greenplum数据库查看表倾斜的方法总结
  16. MyBatisPlus--多数据源
  17. ImmuCellAI | 免疫浸润计算工具 R包学习
  18. 学术人生 | 宾大机器学习PhD:我是如何从头开始写一篇顶级论文的?
  19. MOS管选型注重的参数及使用注意事项-KIA MOS管
  20. Mac系统 下载安装Android studio

热门文章

  1. 根据需求,完成如下代码(按照标准格式写),并在测试类中进行测试?
  2. 听书是怎样的一种体验
  3. java.lang.NoClassDefFoundError: javax/activation/DataSource
  4. 启动计算机引导win10,图文详解win10系统电脑开机引导错误的方案
  5. 前端如何实现搜索关键字的高亮显示
  6. c++ crow入门填坑坑
  7. 超级记忆法(4)——第二小时
  8. Python爬虫的起点!学爬虫从起点开始!
  9. MSBUILD : error MSB4132: The tools version “2.0“ is unrecognized. Available tools versions are “4.0“
  10. 【高德LBS开源组件大赛】地震来了