java5线程框架Executor的用法举例

Executor 是 java5 下的一个多任务并发执行框架(Doug Lea),可以建立一个类似数据库连接池的线程池来执行任务。这个框架主要由三个接口和其相应的具体类组成。Executor、 ExecutorService 和 ScheduledExecutorService 。 

1、 Executor 接口:是用来执行 Runnable 任务的;它只定义一个方法- execute(Runnable command);执行 Ruannable 类型的任务。 

2、 ExecutorService 接口: 继承Executor接口,提供了执行Callable任务和中止任务执行的服务。 

3、 ScheduledExecutorService 接口:继承 ExecutorService 接口,提供了按排程执行任务的服务。 

4、 Executors 类:为了方便使用, 建议使用 Executors的工具类来得到 Executor 接口的具体对象。 

Executors 类有几个重要的方法,在这里简明一下: 

1、 callable(Runnable task): 将 Runnable 的任务转化成 Callable 的任务 

2、 newSingleThreadExecutor(): 产生一个 ExecutorService 对象,这个对象只有一个线程可用来执行任务,若任务多于一个,任务将按先后顺序执行。 

3、 newCachedThreadPool(): 产生一个 ExecutorService 对象,这个对象带有一个线程池,线程池的大小会根据需要调整,线程执行完任务后返回线程池,供执行下一次任务使用。 

4、 newFixedThreadPool(int poolSize): 产生一个 ExecutorService 对象,这个对象带有一个大小为 poolSize 的线程池,若任务数量大于 poolSize ,任务会被放在一个 queue 里顺序执行。 

5、 newSingleThreadScheduledExecutor(): 产生一个 ScheduledExecutorService 对象,这个对象的线程池大小为 1 ,若任务多于一个,任务将按先后顺序执行。 

6、 newScheduledThreadPool(int poolSize): 产生一个 ScheduledExecutorService 对象,这个对象的线程池大小为 poolSize ,若任务数量大于 poolSize ,任务会在一个 queue 里等待执行。 

有关Executor框架其它类的说明请参看JAVA 5 的 API文档 

下面是几个简单的例子,用以示例Executors中几个主要方法的使用。 

1、 Task.java 任务 

2、 SingleThreadExecutorTest.java 单线程执行程序的测试 

3、 CachedThreadPoolTest.java 线程池线程执行程序的测试 

4、 FixedThreadPoolTest.java 线程池线程执行程序的测试(线程数固定) 

5、 DaemonThreadFactory.java 守护线程生成工厂 

6、 MaxPriorityThreadFactory.java 大优先级线程生成工厂 

7、 MinPriorityThreadFactory.java 小优先级线程生成工厂 

8、 ThreadFactoryExecutorTest.java 在自定义线程生成工厂下的测试 

=============== 1、 Task.java 

package Executor; 

//可执行任务 

public class Task implements Runnable { 

// 中断信号 

volatile boolean stop = false; 

// 该任务执行的次数 

private int runCount = 0; 

// 任务标识 

private int taskId; 

public Task(int taskId) { 

this.taskId = taskId; 

System.out.println("Create Task-" + taskId); 

} 

// 执行任务 

public void run() { 

while (!stop) { 

try { 

Thread.sleep(10); 

} catch (InterruptedException e) { 

System.out.println("Task interrupted..."); 

} 

// 线程运行3次后,中断信号置为true 

if (++runCount == 3) 

stop = true; 

// 输出一些语句 

System.out.println("" + Thread.currentThread().toString() + "tttt execute Task-" + taskId + "'s " + runCount 

+ "th run. "); 

} 

} 

} 

=============== 1 end 

=============== 2、 SingleThreadExecutorTest.java 

package Executor; 

import java.util.concurrent.ExecutorService; 

import java.util.concurrent.Executors; 

public class SingleThreadExecutorTest { 

public static void main(String[] args) { 

try { 

// 创建一个单线程执行程序 

ExecutorService executorService = Executors.newSingleThreadExecutor(); 

for (int i =1; i <= 3; i++) { 

executorService.execute(new Task(i)); 

} 

executorService.shutdown(); 

} catch (Exception e) {} 

} 

} 

=============== 2 end 

=============== 3、 CachedThreadPoolTest.java 

package Executor; 

import java.util.concurrent.ExecutorService; 

import java.util.concurrent.Executors; 

public class CachedThreadPoolTest { 

public static void main(String[] args) { 

try { 

// 建新线程的线程池,如果之前构造的线程可用则重用它们 

ExecutorService executorService = Executors.newCachedThreadPool(); 

for (int i =1; i <= 4; i++) { 

executorService.execute(new Task(i)); 

} 

executorService.shutdown(); 

} catch (Exception e) {} 

} 

} 

=============== 3 end 

=============== 4、 FixedThreadPoolTest.java 

package Executor; 

import java.util.concurrent.ExecutorService; 

import java.util.concurrent.Executors; 

public class FixedThreadPoolTest { 

public static void main(String[] args) { 

try { 

// 创建固定线程数的线程池,以共享的无界队列方式来运行这些线程 

ExecutorService executorService = Executors.newFixedThreadPool(2); 

for (int i =1; i <= 5; i++) { 

executorService.execute(new Task(i)); 

} 

executorService.shutdown(); 

} catch (Exception e) {} 

} 

} 

=============== 4 end 

=============== 5、广州软件开发培训 DaemonThreadFactory.java 

package Executor; 

import java.util.concurrent.ThreadFactory; 

public class DaemonThreadFactory implements ThreadFactory { 

//创建一个守护线程 

public Thread newThread(Runnable r) { 

Thread t = new Thread(r); 

t.setDaemon(true); 

return t; 

} 

} 

=============== 5 end 

=============== 6、 MaxPriorityThreadFactory.java 

package Executor; 

import java.util.concurrent.ThreadFactory; 

public class MaxPriorityThreadFactory implements ThreadFactory { 

//创建一个最大优先级的线程 

public Thread newThread(Runnable r) { 

Thread t = new Thread(r); 

//优先级最大、意思是切换到这个线程的概率比其它的低一些 

t.setPriority(Thread.MAX_PRIORITY); 

return t; 

} 

} 

=============== 6 end 

=============== 7、 MinPriorityThreadFactory.java 

package Executor; 

import java.util.concurrent.ThreadFactory; 

public class MinPriorityThreadFactory implements ThreadFactory { 

//创建一个最小优先级的线程 

public Thread newThread(Runnable r) { 

Thread t = new Thread(r); 

//优先级最小、意思是切换到这个线程的概率比其它的低一些 

t.setPriority(Thread.MIN_PRIORITY); 

return t; 

} 

} 

=============== 7 end 

=============== 8、 ThreadFactoryExecutorTest.java 

package Executor; 

import java.util.concurrent.ExecutorService; 

import java.util.concurrent.Executors; 

public class ThreadFactoryExecutorTest { 

public static void main(String[] args) { 

try { 

// 创建一个单线程执行程序 

ExecutorService defaultExecutor = Executors.newCachedThreadPool(); 

ExecutorService daemonExec = Executors 

.newCachedThreadPool(new DaemonThreadFactory()); 

ExecutorService maxPriorityExecutor = Executors 

.newCachedThreadPool(new MaxPriorityThreadFactory()); 

ExecutorService minPriorityExecutor = Executors 

.newCachedThreadPool(new MinPriorityThreadFactory()); 

//用守护线程执行任务 

for (int i = 1; i < 10; i++){ 

daemonExec.execute(new Task(i)); 

} 

//用其它线程执行任务 

for (int j = 10; j <= 20; j++){ 

if (j == 10) 

maxPriorityExecutor.execute(new Task(j)); 

else if (j == 11) 

minPriorityExecutor.execute(new Task(j)); 

else 

defaultExecutor.execute(new Task(j)); 

} 

} catch (Exception e) {} 

} 

} 

每问题每线程:在于它没有对已创建线程的数量进行任何限制,除非对客户端能够抛出的请求速率进行限制。 

无限制创建线程的缺点: 

1.线程生命周期的开销:线程的创建和关闭并不是“免费的”。 

2.资源消耗量:活动线程会消耗系统资源,尤其是内存。 

3.稳定性。 

1 线程池(Thread Pool) 

在java中,任务执行的首要抽象不是Thread,而是Executor。 

public interface Executor { 

/** 

* Executor只是一个简单的接口,但是他却为一个灵活而且强大的框架创造了基础。 

*/ 

void execute(Runnable command); 

} 

这个框架可以用于异步任务执行,而且支持很多不同类型的任务执行策略。它还为任务提交和任务执行之间的解耦提供了标准的方法。
另外,还提供了对生命周期的支持以及钩子函数,可以添加诸如统计收集、应用程序管理机制和监视器等扩展。 1.1 创建/关闭 1.newCachedThreadPool 创建可缓存的线程池,多的话回收,少的话增加,没有限制 N2.ewFixedThreadPool(int nThreads) 创建定长的线程池,每提交一个任务就创建一个线程,直到最大。如果某个以外终止,会补充一个新的 3.newScheduledThreadPool(int corePoolSize) 定长线程池,而且支持定时的以及周期性的任务执行。相当于timer。 4.newSingleThreadExecutor() 单线程化的executor,只创建唯一的工作线程来之心吧任务。如果它意外结束,会有另一个取代它。它会保证任务队列所规定的顺序执行。 5.newSingleThreadScheduledExecutor() 创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 private static final Executor exec=Executors.newFixedThreadPool(100); ServerSocket socket=new ServerSocket(80); while(true){ final Socket connection=socket.accept(); Runnable task=new Runnable(){ public void run(){ handleRequest(connection); } }; exec.execute(exec); } 1.2 ExecutorService 线程如果无法正常关闭http://,则会阻止JVM的结束。线程池中的任务,可能已经完成,可能正在运行,
其他还有在队列中等待执行。关闭的时候可能平缓的关闭,到唐突的关闭(拔掉电源)。
为了解决生命周期的问题,ExecutorService扩展了Executor,并且添加了一些用于生命周期管理的方法。 public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; 。。。。。 } 可以关闭 ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorService。
shutdown() 方法在终止前允许执行以前提交的任务,
而 shutdownNow() 方法阻止等待任务启动并试图停止当前正在执行的任务
。在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。
应该关闭未使用的 ExecutorService 以允许回收其资源。 exec.shutdown(); ExecutorService线程池 java并发编程-Executor框架 1.3 延迟,并且周期性的任务,newScheduledThreadPool Timer的问题: 1.只能创建唯一的线程来执行所有timer任务。 2.如果一个timerTask很耗时,会导致其他TimerTask的时效准确性出问题 3.如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer不会重新恢复。
另外一个Timer中的Task出现异常以后,后面再给这个Timer的任务也将会无法执行。 1.4 结合DelayQueue 如果要自己构建调度服务,那还可以考虑使用DelayQueue,它里面的每个对象低耦合一个延迟时间有关联,
只有过期以后,DelayQueue才能让你执行take操作获取元素。那么当它里面的对象是FutureTask的时候,
就可以构成一个简单的调度队列。 2 Runnable和Future、CallBack 2.1 Runnable Executor框架让定制一个执行策略变得简单,不过想要使用它,你的任务还必须实现Runnable接口。
在许多服务器请求中,都存在一个情况,那就是:单一的客户请求。它能执行一些简单的任务,
但是他不能返回一个值或者抛出受检查的异常。 2.2 Callback 很多任务都会引起计算延迟,包括执行数据库查询、从网络上获取资源、进行复杂的计算。
这些任务Callback抽象更好。它也可以被Executor框架执行 Executors包含很多静态方法,可以吧Runnable和PrivilegedAction封装为Callable。 2.3 FutureTask Runnable和Callable描述的是抽象的计算性任务,这些任务通常是有限的,他们有开始,而且最终会结束。 一个Executor执行的任务有4个周期,创建、提交、开始、完成。由于任务的执行会花很长时间,
我们也希望可以取消任务。 Future描述了任务的生命周期,并提供了相关的方法来获得任务的结果、
取消任务以及检验任务是否完成还是取消。对应的isDone、isCancelled() 方法,它不能后退,一旦完成,
就永远停在完成状态上。用get(等待)获得结果。 /** * @param args * @throws InterruptedException * @throws ExecutionException */ public static void main(String[] args) throws InterruptedException { int threadCounts = 19;// 使用的线程数 long sum = 0; ExecutorService exec = Executors.newFixedThreadPool(threadCounts); List<Callable<Long>> callList = new ArrayList<Callable<Long>>(); // 生成很大的List List<Integer> list = new ArrayList<Integer>(); for (int i = 0; i <= ; i++) { list.add(i); } int len = list.size() / threadCounts;// 平均分割List // List中的数量没有线程数多(很少存在) if (len == 0) { threadCounts = list.size();// 采用一个线程处理List中的一个元素 len = list.size() / threadCounts;// 重新平均分割List } for (int i = 0; i < threadCounts; i++) { final List<Integer> subList; if (i == threadCounts - 1) { subList = list.subList(i * len, list.size()); } else { subList = list.subList(i * len, len * (i + 1) > list.size() ? list.size() : len * (i + 1)); } // 采用匿名内部类实现 callList.add(new Callable<Long>() { public Long call() throws Exception { long subSum = 0L; for (Integer i : subList) { subSum += i; } System.out.println("分配给线程:" + Thread.currentThread().getName() + "那一部分List的整数和为:tSubSum:" + subSum); return subSum; } }); } List<Future<Long>> futureList = exec.invokeAll(callList); for (Future<Long> future : futureList) { sum += future.get(); } exec.shutdown(); System.out.println(sum); } 2.4 和Service的结合 Runnable和Callable类都可以通过Service的submit方法提交,并且返回一个Future,
它表示这个任务,可以获得该任务的执行结果或者取消它。 3 CompletionService 向Executor提交一个批处理任务,并且希望获得结果,那么你将会使用Future,
然后不断的调用isDone来检验是否完成,这样太麻烦,还有更好的方法,那就是完成服务,
CompletionService。poll方法不会等待,返回null。take方法会等待。 它整合了Executor和BlockingQueue的功能,你可以将Callable任务交给他执行,
然后使用类似于队列中的take何poll方法,在结果完整时可用时获得这个结果。
ExecutorCompletionService是它的实现类。 它的实现也比较简单,在构造函数中创建一个BlockingQueue,用它保存结果: private final BlockingQueue<Future<V>> completionQueue; 提交的任务被包装成QueueFuture: private class QueueingFuture extends FutureTask<Void> { QueueingFuture(RunnableFuture<V> task) { super(task, null); this.task = task; } protected void done() { completionQueue.add(task); } private final Future<V> task; } 覆写done方法,将结果置入BlockingQueue。 它与上面获得一堆FutureTask,然后遍历的去get等返回还不一样。它只能一个个获取,
代表有一个拿一个。FutureTask的get可能后面的FutureTask都已经好了,可是有一个还没好,
那就卡在中间了。

线程框架Executor的用法举例的更多相关文章

  1. Java并发——线程池Executor框架

    线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...

  2. Java 线程池 Executor 框架

    在Java中,可以通过new Thread 的方法来创建一个新的线程执行任务,但是线程的创建是非常耗时的,而且创建出来的新的线程都各自运行.缺乏统一的管理,这样的后果是可能导致创建过多的线程从而过度消 ...

  3. Java并发—线程池框架Executor总结(转载)

    为什么引入Executor线程池框架 new Thread()的缺点 每次new Thread()耗费性能 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞 ...

  4. 基础线程机制--Executor线程池框架

    基础线程机制 Executor线程池框架 1.引入Executor的原因 (1)new Thread()的缺点 ​  每次new Thread()耗费性能 ​  调用new Thread()创建的线程 ...

  5. JDK线程池框架Executor源码阅读

    Executor框架 Executor ExecutorService AbstractExecutorService ThreadPoolExecutor ThreadPoolExecutor继承A ...

  6. (转)深入详解Java线程池——Executor框架

    转:https://yq.aliyun.com/articles/633782?utm_content=m_1000015330 在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定 ...

  7. 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结

    <Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...

  8. 第六章并发编程,异步执行框架executor

    异步执行框架executor是一个接口,只有一个方法.接受一个Runnable做为参数,执行任务. 将任务的执行与提交解耦. 1:executor package java.util.concurre ...

  9. Java并发框架:Executor

    介绍 随着当今处理器中可用的核心数量的增加, 随着对实现更高吞吐量的需求的不断增长,多线程 API 变得非常流行. Java 提供了自己的多线程框架,称为 Executor 框架. 1. Execut ...

随机推荐

  1. [terry笔记]redhat5.5_11gR2_RAC_安装

    redhat5.5_11gR2_RAC_安装,这篇主要记录RAC安装的执行步骤,最烦琐的就是前期配置,到后面图形界面runInstaller,asmca,dbca就很容易了. --hostname检查 ...

  2. LaTeX 设置字体颜色

    本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50240179 需要包含宏包: \use ...

  3. SQL的四种语言:DDL、DML、DCL、TCL

    1. DDL(Data Definition Language) 数据库定义语言statements are used to define the database structure or sche ...

  4. SJTU 1319. countColors

    题目描写叙述 知道 psypaint 怎么用吗?在巫女系统全面普及的未来世界.非常少人会知道 psypaint 的使用方法. 而身处在公安局作为监视官的朱同学.为了办案须要研究起了 psypaint ...

  5. datatable 前台和后台数据格式

    datatable是很强大的前台表格插件,前台定义好表格格式后,后台须要返回指定格式的json数据! 例如以下: 首先是js的定义: var oTable = $('#sample_editable_ ...

  6. 二维码框架ZBarSDK的使用和自己定义二维码扫描界面方法

    假设你不知道ZBarSDK怎么用,请下载demo http://download.csdn.net/detail/u013686641/7858917 假设你已经配置好ZBarSDK .那么以下这个类 ...

  7. oracle新手随记10

    1. unpivot注意点:select new_col from (select ename,job,to_char(sal) as sal,null as c from emp)         ...

  8. bzoj1001: [BeiJing2006]狼抓兔子(初识是你最小割)

    1001: [BeiJing2006]狼抓兔子 题目:传送门 题解: 听说这题当初是大难题...可惜当年没有网络流hahahha 现在用网络流的思想就很容易解决了嘛 给什么连什么,注意是双向边,然后跑 ...

  9. nyoj--108--士兵杀敌(一)(区间求和&&树状数组)

    士兵杀敌(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军现在想知 ...

  10. jzoj4196 二分图计数 解题报告(容斥原理)

    Description