4-线程池
来源:互联网 发布:股票分时线数据接口 编辑:程序博客网 时间:2024/06/06 08:40
线程池的基本思想
创建线程对象和清除线程垃圾都会大量占用CPU等系统资源,使用线程池就可以很好的解决资源浪费的问题。
线程池的基本思想:
在系统中开辟一块区域,存放一些待命的线程,这个区域成为线程池。
如果有需要执行的任务,则从线程池中借一个待命的线程来执行指定的任务,任务执行结束在将借的线程归还
这样就避免了大量创建线程对象,浪费CPU、内存资源的问题。
常用线程池类型
固定尺寸的线程池:待命线程的数量是一定,创建线程池后不能改变
优点:实现简单
缺点:
如果要执行的任务数量很多,超过待命线程的数量,有可能造成大量的等待
如果要执行的任务数量很少,大量待命的线程也可能造成内存的浪费
可变尺寸的线程池:待命线程的数量根据任务负载的需要动态变化
优点:
如果等待执行的任务数量很多,系统会自动扩充待命线程的数量,来提高效率
如果等待执行的任务数量很少,系统会自动缩减待命线程的数量,来减少内存消耗
缺点:实现复杂
固定尺寸线程池
创建线程池
获取固定线程池的方法,使用Executors类的静态工厂方法创建线程池:
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个具有固定大小的线程池,如果线程异常终止,将产生新的线程来替代它
public static ExecutorService newSingleThreadExecutor()
创建一个线程池,在同一时刻只可以执行一个任务,使用这个方法可以保证多个任务顺序执行,并且不可以被重新配置为支持多个线程,如果该线程异常终止,将产生新的线程来替代它
两个方法返回的都是ExecutorService接口类型的引用,指向线程池对象,使用它的execute方法使用线程池中的线程执行指定的任务
void execute(Runnable command)
关闭线程池
使用线程池的程序在所有任务结束后并不会自动退出,因为线程池中的线程在执行完任务后并不死亡,而是等待执行新的任务,如果希望在程序在执行完所有任务后退出,需要调用ExecutorService接口中的shutdown方法来关闭线程池
void shutdown()
关闭线程池,不再接受新任务,旧任务结束则关闭线程池中所有的线程(等待所有任务,包括等待队列的任务都完成了才关闭线程池)
List<Runnable> shutdownNow()
无论所有任务是否执行结束,立即关闭线程池,List中为等待执行的任务
public class Main{public static void main(String[] args){ MyTask task1 = new MyTask("task1", 50); MyTask task2 = new MyTask("task2", 50); MyTask task3 = new MyTask("task3", 30); //创建固定大小的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(2); threadPool.execute(task1); threadPool.execute(task2); threadPool.execute(task3); //所有任务都结束后关闭线程池 threadPool.shutdown();}}class MyTask implements Runnable{private int count;private String taskName;public MyTask(String taskName, int count){this.count = count;this.taskName = taskName;}public void run(){System.out.println("\n"+Thread.currentThread().getName()+"开始执行任务"+taskName+">>");for(int i=0;i<count;i++){System.out.print(taskName+"-"+i+" ");}System.out.println("\n"+taskName+"任务执行结束。。");}}
运行结果:
pool-1-thread-1开始执行任务task1>>pool-1-thread-2开始执行任务task2>>task1-0 task2-0 task1-1 task2-1 task1-2 task2-2 task1-3 task2-3 task1-4 task2-4 task1-5 task2-5 task1-6 task2-6 task1-7 task2-7 task1-8 task2-8 task1-9 task2-9 task1-10 task1-11 task1-12 task1-13 task2-10 task1-14 task2-11 task1-15 task2-12 task1-16 task2-13 task1-17 task2-14 task1-18 task2-15 task1-19 task2-16 task1-20 task2-17 task1-21 task2-18 task1-22 task2-19 task1-23 task2-20 task1-24 task2-21 task1-25 task2-22 task2-23 task2-24 task2-25 task2-26 task2-27 task1-26 task2-28 task2-29 task2-30 task1-27 task2-31 task2-32 task1-28 task2-33 task2-34 task2-35 task2-36 task2-37 task2-38 task2-39 task2-40 task2-41 task2-42 task2-43 task2-44 task2-45 task2-46 task2-47 task2-48 task2-49 task2任务执行结束。。task1-29 task1-30 pool-1-thread-2开始执行任务task3>>task3-0 task3-1 task3-2 task3-3 task3-4 task3-5 task3-6 task3-7 task3-8 task3-9 task3-10 task3-11 task3-12 task3-13 task3-14 task3-15 task3-16 task3-17 task3-18 task3-19 task3-20 task3-21 task3-22 task3-23 task3-24 task3-25 task1-31 task3-26 task3-27 task3-28 task3-29 task3任务执行结束。。task1-32 task1-33 task1-34 task1-35 task1-36 task1-37 task1-38 task1-39 task1-40 task1-41 task1-42 task1-43 task1-44 task1-45 task1-46 task1-47 task1-48 task1-49 task1任务执行结束。。
从结果中可以看出,线程池中的两个线程pool-1-thread-1、pool-1-thread-2分别执行了task1、task2,
pool-1-thread-2执行完task2后接着又执行了task3
实际开发中,线程池一般只有一个,用其中的线程完成各种任务。
如果需要执行的任务数量大于线程池的尺寸,则有的任务要进入此线程池的的等待队列
单任务线程池的使用
同一时刻只允许执行一个任务,而且要求任务按照请求的顺序执行
public class Main{public static void main(String[] args){ MyTask task1 = new MyTask("task1", 20); MyTask task2 = new MyTask("task2", 20); MyTask task3 = new MyTask("task3", 10); //创建单任务线程池 ExecutorService singlePool = Executors.newSingleThreadExecutor(); singlePool.execute(task1); singlePool.execute(task2); singlePool.execute(task3); //所有任务都结束后关闭线程池 singlePool.shutdown();}}class MyTask implements Runnable{private int count;private String taskName;public MyTask(String taskName, int count){this.count = count;this.taskName = taskName;}public void run(){System.out.println("\n"+Thread.currentThread().getName()+"开始执行任务"+taskName+">>");for(int i=0;i<count;i++){System.out.print(taskName+"-"+i+" ");}System.out.println("\n"+taskName+"任务执行结束。。");}}
运行结构:
pool-1-thread-1开始执行任务task1>>task1-0 task1-1 task1-2 task1-3 task1-4 task1-5 task1-6 task1-7 task1-8 task1-9 task1-10 task1-11 task1-12 task1-13 task1-14 task1-15 task1-16 task1-17 task1-18 task1-19 task1任务执行结束。。pool-1-thread-1开始执行任务task2>>task2-0 task2-1 task2-2 task2-3 task2-4 task2-5 task2-6 task2-7 task2-8 task2-9 task2-10 task2-11 task2-12 task2-13 task2-14 task2-15 task2-16 task2-17 task2-18 task2-19 task2任务执行结束。。pool-1-thread-1开始执行任务task3>>task3-0 task3-1 task3-2 task3-3 task3-4 task3-5 task3-6 task3-7 task3-8 task3-9 task3任务执行结束。。
创建大小可变的线程池
public static ExecutorService newCachedThreadPool()
创建一个大小可变的线程池,当执行任务时先选取重用缓存已有的空闲线程来完成任务,如果没有空闲线程,则创建新线程
空闲超过60秒的线程将被从线程池中删除
...public static void main(String[] args){ MyTask task1 = new MyTask("task1", 30); MyTask task2 = new MyTask("task2", 30); MyTask task3 = new MyTask("task3", 20); //创建大小可变的线程池 ExecutorService threadPool = Executors.newCachedThreadPool(); threadPool.execute(task1); threadPool.execute(task2); threadPool.execute(task3); //所有任务都结束后关闭线程池 threadPool.shutdown();}...
运行结果:
pool-1-thread-1开始执行任务task1 >>task1-0 task1-1 task1-2 pool-1-thread-2开始执行任务task2 >>task1-3 task1-4 task1-5 task1-6 pool-1-thread-3开始执行任务task3 >>task3-0 task3-1 task3-2 task3-3 task3-4 task3-5 task3-6 task1-7 task3-7 task3-8 task3-9 task2-0 task3-10 task1-8 task3-11 task3-12 task3-13 task3-14 task3-15 task3-16 task3-17 task3-18 task2-1 task3-19 task1-9 task3任务执行结束 。。task2-2 task2-3 task2-4 task2-5 task2-6 task2-7 task2-8 task2-9 task2-10 task2-11 task2-12 task2-13 task2-14 task2-15 task1-10 task2-16 task1-11 task2-17 task2-18 task2-19 task1-12 task2-20 task2-21 task1-13 task2-22 task1-14 task2-23 task1-15 task2-24 task1-16 task1-17 task1-18 task1-19 task1-20 task1-21 task1-22 task1-23 task2-25 task1-24 task2-26 task1-25 task2-27 task1-26 task2-28 task1-27 task2-29 task1-28 task2任务执行结束 。。task1-29 task1任务执行结束 。。
三个任务交替执行,可变尺寸的线程池可以根据任务的多少来自动调整待命线程的数量,优化执行性能。
延迟线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
corePoolSize,线程池中线程的数量
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
创建一个延迟线程池,其中只有一个待命线程
以上两个方法返回的都是ScheduledExecutorService,是ExecutorService的子接口,特有的方法schedule来延迟执行指定的任务
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)//TimeUnit为枚举类型
...public static void main(String[] args){ MyTask task1 = new MyTask("task1", 30); MyTask task2 = new MyTask("task2", 30); MyTask task3 = new MyTask("task3", 20); //创建有时延的线程池 ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2); //创建单线程延时线程池 ScheduledExecutorService singleThreadPool = Executors.newSingleThreadScheduledExecutor(); threadPool.schedule(task1, 1, TimeUnit.SECONDS); threadPool.schedule(task2, 1500, TimeUnit.MILLISECONDS); singleThreadPool.schedule(task3, 2000, TimeUnit.MILLISECONDS); //所有任务都结束后关闭线程池 threadPool.shutdown(); singleThreadPool.shutdown();}...
运行结果:
pool-1-thread-1开始执行任务task1 >>task1-0 task1-1 task1-2 task1-3 task1-4 task1-5 task1-6 task1-7 task1-8 task1-9 task1-10 task1-11 task1-12 task1-13 task1-14 task1-15 task1-16 task1-17 task1-18 task1-19 task1-20 task1-21 task1-22 task1-23 task1-24 task1-25 task1-26 task1-27 task1-28 task1-29 task1任务执行结束 。。pool-1-thread-2开始执行任务task2 >>task2-0 task2-1 task2-2 task2-3 task2-4 task2-5 task2-6 task2-7 task2-8 task2-9 task2-10 task2-11 task2-12 task2-13 task2-14 task2-15 task2-16 task2-17 task2-18 task2-19 task2-20 task2-21 task2-22 task2-23 task2-24 task2-25 task2-26 task2-27 task2-28 task2-29 task2任务执行结束 。。pool-2-thread-1开始执行任务task3 >>task3-0 task3-1 task3-2 task3-3 task3-4 task3-5 task3-6 task3-7 task3-8 task3-9 task3-10 task3-11 task3-12 task3-13 task3-14 task3-15 task3-16 task3-17 task3-18 task3-19 task3任务执行结束 。。
自定义参数的线程池
使用ThreadPoolExecutor类(实现了ExecutorService)来实现自定义的线程池,当有新任务到达时,按照以下规则处理:
1)如果当前线程池中的线程数量比规定标准值少,则倾向于创建线程;
2)如果当前线程池中的线程数量比规定标准值多,则倾向于把新的任务放到队列中;如果队列已满,并且线程数量没有超过最大值,则创建新线程。
3)如果当前线程池中的线程数量已达最大值,且队列已满,则请求被拒绝。
4)如果空闲线程超过预设的存活时间,则将空闲线程对象销毁。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ThreadPoolExecutor类一些常用的方法:
public int getCorePoolSize() 获取线程池的标准大小
public int getActiveCount() 返回线程池中正在执行任务的线程数量
public int getPoolSize() 获取线程池的当前大小
public int getMaximumPoolSize() 获取线程池的最大大小
public BlockingQueue<Runnable> getQueue() 返回线程池的工作等待队列
...public static void main(String[] args){ MyTask task1 = new MyTask("task1", 30); MyTask task2 = new MyTask("task2", 30); MyTask task3 = new MyTask("task3", 20); MyTask task4 = new MyTask("task4", 20); //创建工作等待队列 BlockingQueue workQueue = new ArrayBlockingQueue(3); //创建自定义线程池 ThreadPoolExecutor myThreadPool = new ThreadPoolExecutor( 2, 4, 100, TimeUnit.SECONDS, workQueue); myThreadPool.execute(task1); myThreadPool.execute(task2); myThreadPool.execute(task3); myThreadPool.execute(task4); //所有任务都结束后关闭线程池 myThreadPool.shutdown();}...
运行结果:
pool-1-thread-1开始执行任务task1 >>task1-0 task1-1 task1-2 task1-3 task1-4 pool-1-thread-2开始执行任务task2 >>线程池的当前线程数:2task2-0 task2-1 task2-2 task2-3 task2-4 task2-5 task2-6 task2-7 task2-8 task2-9 task2-10 task2-11 task2-12 task2-13 task2-14 task2-15 task2-16 task2-17 task2-18 task2-19 task2-20 task1-5 task2-21 task1-6 task2-22 task1-7 task2-23 task1-8 task2-24 task1-9 task2-25 task1-10 task2-26 task1-11 task2-27 task1-12 task2-28 task2-29 task1-13 task2任务执行结束 。。task1-14 task1-15 pool-1-thread-2开始执行任务task3 >>task1-16 task3-0 task1-17 task3-1 task3-2 task3-3 task1-18 task3-4 task1-19 task3-5 task1-20 task3-6 task1-21 task3-7 task1-22 task3-8 task1-23 task3-9 task1-24 task3-10 task1-25 task3-11 task1-26 task3-12 task1-27 task3-13 task1-28 task3-14 task1-29 task3-15 task1任务执行结束 。。task3-16 pool-1-thread-1开始执行任务task4 >>task3-17 task4-0 task3-18 task4-1 task3-19 task4-2 task3任务执行结束 。。task4-3 task4-4 task4-5 task4-6 task4-7 task4-8 task4-9 task4-10 task4-11 task4-12 task4-13 task4-14 task4-15 task4-16 task4-17 task4-18 task4-19 task4任务执行结束 。。
- 线程4:线程池
- 线程学习4——线程池
- Java线程(4)线程池
- 使用线程池(4)
- 4-线程池
- 线程与线程池
- 线程池 线程优先级
- Executor线程,线程池
- 线程、多线程、线程池
- IOS-线程、线程池
- Java线程:线程池
- 线程和线程池
- 线程、多线程、线程池
- 线程、多线程、线程池
- 线程(六)线程池
- ExecutorService(线程池)+线程
- 线程和线程池
- 线程&线程池 简略
- 数据库知识——基础篇
- java学习 十四、关键字汇总
- caffe---make发生的错误和解决办法1
- Volley的源码分析
- OpenvSwitch常用命令(全)
- 4-线程池
- 设置页面滚动到某div处
- Java ssh 框架 hibernate 详细理解
- IDEA添加Jar包和JSP页面报 cannot resolve method getParameter("")
- Windows版本宏的定义引起的编译错误
- UVA10881解题报告
- 【论文翻译】SegNet: A Deep Convolutional Encoder-Decoder Architecture for Image Segmentation
- 牛客网(四)
- mysql基础:4、mysql支持的数据类型