标签:
一个优秀的软件不会随意的创建很销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互。因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理。
JDK提供了四种不同的线程池给程序员使用
首先使用线程池,需要用到ExecutorService接口,该接口有个抽象类AbstractExecutorService对其进行了实现,ThreadPoolExecutor进一步对抽象类进行了实现。最后JDK封装了一个Executor类对ThreadPoolExecutor进行实例化,因此通过Executor能够创建出具有如下四种特性的线程池
1. 无下界线程池
ExecutorService threadPool= Executors.newCachedThreadPool( ); 当线程数不足时,线程池会动态增加线程进行后续的任务调度
2. 固定线程数的线程池
ExecutorService threadPool= Executors.newFixedThreadPool(3); 创建具有固定线程数:3个的线程池
3. 单线程线程池
ExecutorService threadPool= Executors.newSingleThreadScheduledExecutor( );创建单例线程池,确保线程池内恒定有1条线程在工作
4. 调度线程池
ScheduledExecutorService threadPool= Executors.newSingleThreadScheduledExecutor( ); 创建一个定长线程池,定时或周期性地执行任务
1 package com.scl.thread.threadPool; 2 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.ScheduledExecutorService; 5 import java.util.concurrent.TimeUnit; 6 7 public class ScheduledThreadPool 8 { 9 public static void main(String[] args) 10 { 11 // 创建定时调度线程池 12 ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor(); 13 // 定时执行Runnable 14 threadPool.scheduleAtFixedRate(new Runnable() 15 { 16 17 @Override 18 public void run() 19 { 20 System.out.println("do some big Scheduled"); 21 } 22 }, 10, 3, TimeUnit.SECONDS); 23 } 24 }
使用线程池也比较简单,只要往线程池里面提交"任务"即可,一般使用对象.submit的方法进行,如下:
① threadPool.submit(Callable<T>task);
Callable跟Runnable接口一样在使用接口时会自动调用里面的call方法。与Runnable接口不一样的地方在于run方法不能返回内容,call方法含有返回参数,在外部可以通过Future 接口来接受线程返回的结果。如:Future<String> future = threadPool.submit(new MyTask( ));
② threadPool.submit(Runnable task);
由这个签名可以看出,同样地可以往线程池里面扔入Runnable接口实例。
这如上面所说,线程池的使用就是减少程序员对线程的启动和关闭。把线程的创建及关闭交给线程池来完成。因此使用线程池来完成线程的经典问题:生产者-消费者模型。
模型简介:该模型是一个典型的排队内容。模型分为三个主要角色:生产者、消费者、仓库。生产者和消费者共享仓库信息,①当仓库里面的产品满了,停止生产等待消费者去消费到足够的量再进行生产 ②当仓库里面的产品为空,等待生产者生产后再进行销售 ③仓库负责承载产品内容
根据模型内容,做成了一个车位管理的例子。分为三个角色:持车人(CarOwner)、保安(Secure)、车库(CarPark)。不同的持车人把车驶入到车库,保安负责记录车辆离开车库的数量。车库容量固定,如果车库为空保安可以通知持车人把车驶入车库。如果车库满了,保安告知持车人等待另外的持车人把车驾驶出来。车库使用一个列表对入库的车信息进行记录。
因此有如下类图:
1 package com.scl.thread.threadPool.CarParkManager; 2 3 public class CarOwner implements Runnable 4 { 5 private int driverInNum; 6 private CarPark carPark; 7 8 public CarOwner(CarPark carPark) 9 { 10 this.carPark = carPark; 11 } 12 13 @Override 14 public void run() 15 { 16 carPark.driverIn(driverInNum); 17 } 18 19 public int getDriverInNum() 20 { 21 return driverInNum; 22 } 23 24 public void setDriverInNum(int driverInNum) 25 { 26 this.driverInNum = driverInNum; 27 } 28 }
1 package com.scl.thread.threadPool.CarParkManager; 2 3 public class Car 4 { 5 private String id; 6 private String name; 7 8 public Car(String id, String name) 9 { 10 this.id = id; 11 this.name = name; 12 } 13 14 }
1 package com.scl.thread.threadPool.CarParkManager; 2 3 public class Secure implements Runnable 4 { 5 private int driverOutNum; 6 7 private CarPark carPark; 8 9 public Secure(CarPark carPark) 10 { 11 this.carPark = carPark; 12 } 13 14 public int getDriverOutNum() 15 { 16 return driverOutNum; 17 } 18 19 public void setDriverOutNum(int driverOutNum) 20 { 21 this.driverOutNum = driverOutNum; 22 } 23 24 @Override 25 public void run() 26 { 27 carPark.driverOut(driverOutNum); 28 } 29 }
1 package com.scl.thread.threadPool.CarParkManager; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 6 public class Client 7 { 8 9 public static void main(String[] args) 10 { 11 // 设置车库最大值 12 CarPark carPark = new CarPark(5); 13 // 创建线程池 14 ExecutorService threadPool = Executors.newCachedThreadPool(); 15 // 创建三个持车人 16 CarOwner cw1 = new CarOwner(carPark); 17 CarOwner cw2 = new CarOwner(carPark); 18 CarOwner cw3 = new CarOwner(carPark); 19 // 设置需要驶入的车辆数目 20 cw1.setDriverInNum(3); 21 cw2.setDriverInNum(3); 22 cw3.setDriverInNum(1); 23 24 // 创建三个保安 25 Secure s1 = new Secure(carPark); 26 Secure s2 = new Secure(carPark); 27 Secure s3 = new Secure(carPark); 28 s1.setDriverOutNum(1); 29 s2.setDriverOutNum(2); 30 s3.setDriverOutNum(1); 31 32 threadPool.submit(cw1); 33 threadPool.submit(cw2); 34 threadPool.submit(cw3); 35 threadPool.submit(s1); 36 threadPool.submit(s2); 37 threadPool.submit(s3); 38 39 } 40 41 }
由上述代码可见,使用线程池和使用Thread类进行提交没有太大的差异。JDK5提供了一个阻塞队列的,能够更好地模拟生产者-消费者模型。后续再进行总结。
以上为线程池的总结内容,如有错漏烦请指出纠正。
标签:
原文地址:http://www.cnblogs.com/doucheyard/p/5752297.html