初试

今天做一个上传excel,后台异步导入数据功能,使用ExecutorService

private final ExecutorService m_longPollingService;

public TaskExecutor(){
m_longPollingService = Executors.newSingleThreadExecutor(
ImportThreadFactory.create("ImportTask", true));;
} public void execute(TaskParam taskParam){
m_longPollingService.execute(new SingleImportTask(taskParam));
}
private class SingleImportTask implements Runnable{
}
 

壹旦线程把任务委托给 ExecutorService,该线程就会继续执行与运行任务无关的其它任务。

Executors:工厂类,创建下面四种线程池

ExecutorService方法

1:execute(Runnable):这个方法有个问题,就是没有办法获知task的执行结果。如果我们想获得task的执行结果,我们可以传入一个Callable的实例(下面会介绍)。

2:submit(Runnable):submit(Runnable)execute(Runnable)区别是前者可以返回一个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执行完毕,

Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
}); future.get(); //returns null if the task has finished correctly.
3:submit(Callable)submit(Runnable)类似,也会返回一个Future对象,但是除此之外,submit(Callable)接收的是一个Callable的实现,Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,而Runnable接口中的run()方法是void的,没有返回值。

shutdown方法:平滑的关闭ExecutorService,当此方法被调用时,ExecutorService停止接收新的任务并且等待已经提交的任务(包含提交正在执行和提交未执行)执行完成。当所有提交任务执行完毕,线程池即被关闭。

awaitTermination方法:接收人timeout和TimeUnit两个参数,用于设定超时时间及单位。当等待超过设定时间时,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用。
 

ExecuteService 服务的关闭

当使用 ExecutorService 完毕之后,我们应该关闭它,这样才能保证线程不会继续保持运行状态。 
举例来说,如果你的程序通过 main() 方法启动,并且主线程退出了你的程序,如果你还有壹個活动的 ExecutorService 存在于你的程序中,那么程序将会继续保持运行状态。存在于 ExecutorService 中的活动线程会阻止Java虚拟机关闭。
为了关闭在 ExecutorService 中的线程,你需要调用 shutdown() 方法。ExecutorService 并不会马上关闭,而是不再接收新的任务,壹但所有的线程结束执行当前任务,ExecutorServie 才会真的关闭。所有在调用 shutdown() 方法之前提交到 ExecutorService 的任务都会执行。
如果你希望立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这個方法会尝试马上关闭所有正在执行的任务,并且跳过所有已经提交但是还没有运行的任务。但是对于正在执行的任务,是否能够成功关闭它是无法保证的,有可能他们真的被关闭掉了,也有可能它会壹直执行到任务结束。这是壹個最好的尝试。

传统线程 new Thread的弊端

执行一个异步任务你还只是如下new Thread吗?

new Thread(new Runnable() {

    @Override
public void run() {
// TODO Auto-generated method stub
}
}).start();

那你就out太多了,new Thread的弊端如下:
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

四种模式

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
(1). newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
} cachedThreadPool.execute(new Runnable() { @Override
public void run() {
System.out.println(index);
}
});
}

线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
 
(2). newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() { @Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}

因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。
 
(3) newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() { @Override
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);

表示延迟3秒执行。
 
定期执行示例代码如下:

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);

表示延迟1秒后每3秒执行一次。
ScheduledExecutorService比Timer更安全,功能更强大,后面会有一篇单独进行对比。
 
(4)、newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() { @Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}

结果依次输出,相当于顺序执行各个任务。
现行大多数GUI程序都是单线程的。Android中单线程可用于数据库操作,文件操作,应用批量安装,应用批量删除等不适合并发但可能IO阻塞性及影响UI线程响应的操作。

最新文章

  1. Android笔记:真机调试
  2. HDU 5818:Joint Stacks(stack + deque)
  3. 【转载】Oracle实例和Oracle数据库(Oracle体系结构)
  4. java 名词解释等
  5. Identity-第二章
  6. Hibernate中的一对多关系详解(2)
  7. poj 3671 Dining Cows (Dp)
  8. 我的创业劲儿,无可阻挡-JAVA学院张孝伟
  9. 关于JS面向对象中原型和原型链以及他们之间的关系及this的详解
  10. #云栖大会# 移动安全专场——APP加固新方向(演讲速记)
  11. Python matplotlib.pyplot
  12. java用POI操作excel——随便写一下,最基础的东西
  13. Xamarin.Android 启动页
  14. JavaScript术语:shim 和 polyfill
  15. Objective-C中的一些特殊的数据类及NSLog的输出格式
  16. 安装XP时BIOS的设置(ahci ide)
  17. 解决python中csv文件中文写入问题
  18. CSS字体无法设置成功的问题
  19. 【shell 练习5】编写简单的多级菜单
  20. Linux(ubuntu 12.04桌面版) 搭建Android开发环境

热门文章

  1. pandas+mysql+excel 数据处理
  2. 无法安装 Microsoft Visual Studio 2010 Service Pack 1
  3. url的进行传参拼接
  4. 斐波那契数列,跳台阶(dp思想)
  5. C# 文件打印
  6. 在C语言中如何嵌入python脚本
  7. blockchain notes
  8. eclipse——Maven创建JavaWeb工程
  9. MVC值提供组件ValueProvider的继承关系
  10. (转)15个非常棒的jQuery无限滚动插件【瀑布流效果】