说到java开发,免不了跟多线程打交道。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象用Executor在构造器中。

ExecutorService,是一个接口,继承了Executor;

Executor,只有一个方法:

public interface Executor {
void execute(Runnable command);
}

Executors提供了4中创建线程池:

public static ExecutorService newCachedThreadPool(); 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

public static ExecutorService newFixedThreadPool(int nThreads); 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个定长线程池,支持定时及周期性任务执行。

public static ExecutorService newSingleThreadExecutor(); 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

通过Executors的以上四个静态工厂方法获得 ExecutorService实例,而后调用该实例的execute(Runnable command)方法即可。一旦Runnable任务传递到execute()方法,该方法便会自动在一个线程上执行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ExecutorTest {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
//ExecutorService executorService = Executors.newFixedThreadPool(3);
// ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 3; i++){
RunnableTest method = new RunnableTest();
executorService.execute(method);
System.out.println("########" + i + "########");
}
executorService.shutdown();
}
}
public class RunnableTest implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName() + "线程执行");
}
}

输出结果:

########0########
########1########
########2########
pool-1-thread-2线程执行
pool-1-thread-3线程执行
pool-1-thread-1线程执行

任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。并且Callable的call()方法只能通过ExecutorService的submit(Callable<T> task) 方法来执行,并且返回一个 <T>Future<T>,是表示任务等待完成的 Future。

下面给出一个Executor执行Callable任务的示例代码

public class ExecutorTest {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
//ExecutorService executorService = Executors.newFixedThreadPool(3);
// ExecutorService executorService = Executors.newSingleThreadExecutor();
List<Future<String>> resultList = new ArrayList<Future<String>>();
for (int i = 0; i < 6; i++){
CallableTest method = new CallableTest(i);
Future<String> future = executorService.submit(method);
System.out.println("########" + i + "########");
resultList.add(future);
} //遍历任务的结果
for (Future<String> fs : resultList){
try{
//Future返回如果没有完成,则一直循环等待,直到Future返回完成
while(!fs.isDone());
//打印各个线程(任务)执行的结果
System.out.println(fs.get());
}catch(InterruptedException e){
e.printStackTrace();
}catch(ExecutionException e){
e.printStackTrace();
}finally{
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务
executorService.shutdown();
}
}
}
}
import java.util.concurrent.Callable;

public class CallableTest implements Callable<String>{

    private int id; 

    public CallableTest(int id){
this.id = id;
} @Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName() + "线程执行");
return Thread.currentThread().getName() + "线程执行" + "返回id=" + id;
}
}

输出结果:

pool-1-thread-1线程执行返回id=0
pool-1-thread-2线程执行返回id=1
pool-1-thread-3线程执行返回id=2
pool-1-thread-4线程执行返回id=3
pool-1-thread-2线程执行返回id=4
pool-1-thread-4线程执行返回id=5

从结果中可以同样可以看出,submit也是首先选择空闲线程来执行任务,如果没有,才会创建新的线程来执行任务。另外,需要注意:如果Future的返回尚未完成,则get()方法会阻塞等待,直到Future完成返回,可以通过调用isDone()方法判断Future是否完成了返回。

线程池ExecutorService的更多相关文章

  1. PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束

    PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束 ExecutorService并没有提供什么 isDone()或者isComplete()之类的方法. 作者Atti ...

  2. [Java线程] Java线程池ExecutorService

    示例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.u ...

  3. 【Java线程】Java线程池ExecutorService

    示例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.u ...

  4. Java线程池ExecutorService和CountDownLatch的小例子

    import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java ...

  5. 多线程 线程池 ExecutorService

    package org.zln.thread; import java.util.Date; import java.util.concurrent.ExecutorService; import j ...

  6. Java中的线程池ExecutorService

    示例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.u ...

  7. (转)线程池 ExecutorService 详细介绍以及注意点区别

    线程池 ExecutorService 相信java开发都用到,这里做个简单笔记 一 Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池 ...

  8. 线程池(ExecutorService)初体验

    背景:查询月统计数据,因为查询日统计数据功能已经实现.月统计数据,只是参一个List(date) 参数,for循环调用日统计,然后把结果整合就OK. 问题:单线程跑  太耗时间 解决方案:使用多线程, ...

  9. 线程池ExecutorService的使用及其正确关闭方法

    创建一个容量为5的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); 向线程池提交15个任务,其实就是通过线程 ...

随机推荐

  1. jquery 之选择器

    一.基本: HTML代码: <p class="p1">p段落</p> <h class="h1">h标签</h> ...

  2. iOS开发中多线程间关于锁的使用

    为什么需要使用锁,当然熟悉多线程的你,自然不会感到陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? main.m 1 int main(int argc, const ch ...

  3. 史航416第九次作业&总结

    一.知识点总结: 1.二维数组定义的形式:类型名 数组名[行长度] [列长度] 例如:int a[3][2]:定义一个二维数组a,3行2列,6个元素: 2.二维数组引用的形式:类型名 数组名[行下标] ...

  4. cdnbest节点安装后连不上主控常见问题

    1. 查看节点程序是否启动 ps -aux |grep kangle 2. 如果节点程序都有启动,可查看日志,节点连接的是不是你帐号的uid帐号或者是否有其他报错信息 tail -f /var/log ...

  5. Odoo 中的 Controller

    来自  Odoo处理HTTP请求的接口用的Contoller类,封装于web模块中. --------------------------------------------------------- ...

  6. Winform GDI+ 相关资料

    在Visual Studio 2010中定义GDI+自定义控件——自定义控件介绍 http://www.cnblogs.com/zhangdong/archive/2010/05/20/1740177 ...

  7. FZU 1686 神龙的难题 (重复覆盖)

    Problem 1686 神龙的难题 Accept: 397    Submit: 1258Time Limit: 1000 mSec    Memory Limit : 32768 KB  Prob ...

  8. 关于dp dip dpi px

    在Android开发中,屏幕适配是一件非常让人头疼的事情.有时候在这个机型上调试的漂漂亮亮的UI界面,换一部手机就丑的不忍直视.但为了我们软件更好的用户体验,我们必须适应Android市场上形形色色的 ...

  9. C++常用输出 cout、cerr、clog

    三者在C++中都是标准IO库中提供的输出工具: cout:写到标准输出的ostream对象: cerr:输出到标准错误的ostream对象,常用于程序错误信息: clog:也是输出标准错误流(这点儿和 ...

  10. 【经验】ansible 批量推送公钥

    1.使用 ssh-keygen -t rsa生成密钥对 ssh-keygen -t rsa 2.推送单个公钥到远程机器 格式: ssh-copy-id -i ~/.ssh/id_rsa.pub use ...