java并发编程第四章 线程执行器(1)
来源:互联网 发布:美国的种族歧视 知乎 编辑:程序博客网 时间:2024/05/19 22:52
本篇博客是java并发编程实战手册中的第四章前三节,主要说明并发框架----执行器
1.创建线程执行器
在开发大并发程序中,如果单纯的创建Runnable或Thread对象将非常麻烦,而且需要管理这样的劣势:
1.必须实现所有与Thread对象管理相关的代码,比如线程的创建,结束以及结果的获取。
2.需要为每一个任务创建一个Thread对象,如果需要执行大量的任务,这将大大的影响应用程序的处理能力。
3.计算机的资源需要高效的进行控制和管理,如果创建过多的线程,将会导致系统负荷过重。
java5 后提供了一套机制解决这些问题,称为执行器框架(Executor FrameWork),围绕着Executor接口和其子接口ExecutorService,
以及实现这两个接口的ThreadPoolExecutor类展开。
这套机制分离了任务的创建和运行,通过使用执行器,仅需要实现Runnable接口的对象,然后将这些对象发送给执行器就行。
1.执行器会创建所需要的线程,来负责这些Runnable对象的创建,实例化以及运行。
2.执行器使用线程池来提高应用程序的性能,当发送一个任务给执行器时,执行器会尝试使用线程池中的线程来执行这个任务,
避免了不断创建和销毁线程而导致系统性能下降。
3.执行器框架带有一个可以返回结果的Callable接口,相对于Runnable的优势就是这个,提供了两点优势:
1.这个接口中的方法只有一个call(),可以返回结果。
2.当发送一个Callable对象给执行器时,将获得一个实现了Future接口的对象,可以使用这个对象来控制Callable对象的状态和结果。
线程执行器的主要方法:
1.getPoolSize():返回执行器线程池中实际线程的数量
2.getActiveCount():返回执行器中正在执行的任务线程的数量。
3.getCompletedTaskCount():返回执行器已经完成的任务数量。
4.execute(Runnable command):在未来摸个时间执行给定的命令,该命令可能在新的线程,已入池的线程或者正在调用的线程中执行,
者由Executor实现决定。
实例代码:
1.Task 模拟web任务
public class Task implements Runnable{private Date initDate;private String name;public Task(String name) {initDate = new Date();this.name = name;}@Overridepublic void run() {System.out.printf("%s: Task %s: created on: %s\n",Thread.currentThread().getName(),name,initDate);System.out.printf("%s Task %s : started on %s\n",Thread.currentThread().getName(),name,new Date());try{Long duration = (long)(Math.random() * 10);System.out.printf("%s: Task %s: Doing a task during %d seconds\n",Thread.currentThread().getName(),name,duration);TimeUnit.SECONDS.sleep(duration);}catch(Exception e){e.printStackTrace();}System.out.printf("%s Task %s : Finished on: %s\n",Thread.currentThread().getName(),name,new Date());}}
2.Server 模拟服务器处理
public class Server {private ThreadPoolExecutor executor;public Server(){//创建具有缓存功能的线程池executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();}public void executeTask(Task task){System.out.println("Server: A new task has arrived!");executor.execute(task); //调用执行器的execute()方法将任务发送给TaskSystem.out.printf("Server: Pool Size : %d\n",executor.getPoolSize());System.out.printf("Server: Active Count: %d\n",executor.getActiveCount());System.out.printf("Server: Completed Tasks: %d\n",executor.getCompletedTaskCount());}public void endServer(){executor.shutdown(); //启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。}}
3.Main 测试类
public class Main {public static void main(String[] args) {Server server = new Server();for(int i =0 ;i< 100;i++){Task task = new Task("Task "+i);server.executeTask(task);}server.endServer();}}
2.创建固定大小的线程执行器
Executor工厂类提供了一个方法来创建一个固定大小的线程执行器。这个执行器有一个线程数量的最大值,
如果发送超过这个最大值的任务
给执行器,执行器将不再创建额外的线程,剩下的任务将被阻塞到执行器有空闲的线程可用。
这个特性可以保证执行器不会给应用程序带来性能问题。
executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(5); //创建有五个线程的线程池
这里使用了一些ThreadPoolExecutor中的方法:
1.getPoolSize():返回执行器中线程的实际数量
2.getActiveCount():返回执行器正在执行任务的线程数量。
说明:Executors工厂类也提供newSingleThreadExecutor()方法。这是一个创建固定大小的线程执行器的一个极端场景。
将创建一个只有单个线程的执行器。因此
这个执行器在同一时间执行一个任务。
本节测试类与上一节相同修改Server类的构造函数即可创建固定大小的线程执行器
public Server(){//创建具有缓存功能的线程池executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);}3.在执行器中执行任务并返回结果
执行器框架的两个接口实现该实例的效果,同时也是可以运行并发任务并返回结果的优势。
1.Callable:声明了一个call()方法。可以在这个方法里实现任务的具体逻辑操作。是个泛型接口,
必须声明call方法返回的数据类型。
2.Future:这个接口声明了一些方法获取由Callable对象产生的结果,并管理它们的状态。
Future接口中的主要方法:
1.cancel(boolean mayInterrupteIfRunning) :试图取消对此任务的执行。如果任务完成或者已经取消,或者由于其他原因而无法取消,
则此尝试将失败。当调用cancel方法时,如果调用成功,而此任务尚未启动,则此任务将永不运行。如果任务已经启动,
则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。
2.isCancel():如果在任务正常完成前将其取消,则返回true.
3.isDone():如果任务已经完成,则返回true,可能由于正常终止,异常或者取消而完成,在所有这些情况中,此方法都将返回true。
4.get():如果有必要,将等待计算完成,然后获取其结果。
5.get(long timeout,TimeUnit unit):如果有必要,最多等待为使计算机完成所给定的时间后,获取其结果。
一般是获取call()方法返回的结果。
如果call()方法抛出异常,该方法也会抛出异常。
Executor的submit()方法会返回一个带泛型的Future对象。由Future对象管理线程返回的结果。
1.求n的阶乘
/** * * @author fcs * @date 2015-5-5 * 描述:在执行器中执行任务并返回结果 * 说明:多线程执行任务可以返回结果需要借助两个接口 * 1.Callable接口,2.Future接口 * 这里实现Callable接口 */public class FactorialCalculator implements Callable<Integer>{private Integer number;public FactorialCalculator(Integer number) {super();this.number = number;}@Overridepublic Integer call() throws Exception {int result = 1;if((number ==0)||(number ==1)){result = 1;}else{for(int i =2; i<= number;i ++){result *= result;TimeUnit.MILLISECONDS.sleep(20);}}System.out.printf("%s: %d\n",Thread.currentThread().getName(),result);return result;}}
2.Main测试类
public class Main { public static void main(String[] args) { ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(2); List<Future<Integer>> resultList = new ArrayList<Future<Integer>>(); Random random = new Random(); for(int i =0;i< 10;i++){ Integer number = random.nextInt(10); FactorialCalculator fc = new FactorialCalculator(number); //这个方法返回一个Future<Integer>对象来管理任务和得到的最终结果 Future<Integer> result = executor.submit(fc); resultList.add(result); } //创建一个do循环来监控执行器的状态 do{ System.out.printf("Main: Number of Completed Tasks: %d\n",executor.getCompletedTaskCount()); for(int i =0;i < resultList.size();i++ ){ Future<Integer> result = resultList.get(i); //通过isDone()方法可以检查任务是否完成 System.out.printf("Main: Task %d: %s\n",i,result.isDone()); } try{ TimeUnit.MILLISECONDS.sleep(50); }catch(Exception e){ e.printStackTrace(); } }while(executor.getCompletedTaskCount() < resultList.size()); System.out.println("Main result "); for(int i =0 ;i< resultList.size();i++){ Future<Integer>result = resultList.get(i); Integer number = null; try {//对于每个Future来讲,通过get方法将得到由任务返回的Integer对象number = result.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.printf("Main: Task %d: %d\n",i,number); } executor.shutdown(); //调用该方法结束执行。否则线程会继续执行下去的。 }}
本篇实例比较简单,就不贴测试结果了。
0 0
- java并发编程第四章 线程执行器(1)
- java并发编程第四章 线程执行器(2)
- java并发编程第四章线程执行器(3)
- java并发编程第四章 线程执行器(4)
- java并发编程第四章 线程执行器(5)
- java并发编程之线程执行器
- Java7并发编程指南——第四章:线程执行器
- Java并发编程-16-线程执行器-Executor Framework
- Java并发编程类学习三(线程的执行)
- 第四章线程执行器
- 并发编程--创建线程执行器
- java并发编程第四章 总结
- Java并发编程之线程管理(线程创建1)
- java编程思想---第四章(控制执行流程)
- Java并发编程:线程的创建和执行
- Java并发编程示例(六):等待线程执行终止
- 《Java编程思想第四版》笔记---21章(1) 并发
- Java编程思想第四版-第四章(控制执行流程 )笔记
- IOS开发入门书籍
- hdu 1250 Hat's Fibonacci
- 10110 - Light, more light
- C++ 虚函数 剖析
- 【leetcode】Gas Station
- java并发编程第四章 线程执行器(1)
- 有深度,面试有用的题
- java基础 第5章 隐藏实施过程
- C++:模板实参推断及引用折叠
- boost内存管理机制
- 丑数
- 图形处理(十)测地极坐标参数化
- respondsToSelector使用
- 设计,素材