线程池
线程池就是一个线程的容器【可以是链表,数组等】。
作用
作用就是限制系统中执行线程的数量,可以自动或手动设置线程数量,以达到最佳效果【少了浪费系统资源,多了消耗资源(每个线程需要大约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里面线程池的顶级接口是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) {
// 创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
// 将线程放入到线程池中
timer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("i'm adanac");
}
}, 1, 1, TimeUnit.SECONDS);
timer.scheduleAtFixedRate(new Runnable() {
@Override
public 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;
}
}
【可能的运行结果】:(运行不大正确)