分享

java线程池

 老匹夫 2014-01-23

java线程池

 

ExecutorService是线程池的一个服务,可以随时关闭线程池,是继承Executor的。Executors是个工厂类,专门创建各种线程池。

Android常用的线程池有一下几种,在Executors里面对应的方法:

1. newFixedThreadPool

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。 

-newFixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程 

-其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子 

-和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP或UDP IDLE机制之类的),所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器 

-从方法的源代码看,cache池和fixed 池调用的是同一个底层池,只不过参数不同: 

fixed池线程数固定,并且是0秒IDLE(无IDLE) 

cache池线程数支持0-Integer.MAX_VALUE(显然完全没考虑主机的资源承受能力),60秒IDLE  

  ExecutorService pool = Executors.newFixedThreadPool(2); 

  //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 

  Thread t1 = new MyThread(); 

  Thread t2 = new MyThread(); 

  Thread t3 = new MyThread(); 

  Thread t4 = new MyThread(); 

  Thread t5 = new MyThread(); 

  //将线程放入池中进行执行 

  pool.execute(t1); 

  pool.execute(t2); 

  pool.execute(t3); 

  pool.execute(t4); 

  pool.execute(t5);

 

2. newCachedThreadPool

创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。

-缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中 

-缓存型池子通常用于执行一些生存期很短的异步型任务 

因此在一些面向连接的daemon型SERVER中用得不多。 

-能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。 

  注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止。

 

3. newSingleThreadExecutor

创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。

-单例线程,任意时间池中只能有一个线程 

-用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)

 

4.newScheduledThreadPool 

-调度型线程池 

-这个池子里的线程可以按schedule依次delay执行,或周期执行

 

 

这三个方法都返回了一个ExecutorService类型的对象。实际上,ExecutorService是一个接口,它的submit()方法负责接收任务并交与线程池中的线程去运行。submit()方法能够接受Callable和Runnable两种类型的对象。它们的用法和区别如下: 

Runnable接口:继承Runnable接口的类要实现它的run()方法,并将执行任务的代码放入其中,run()方法没有返回值。适合于只做某种操作,不关心运行结果的情况。

Callable接口:继承Callable接口的类要实现它的call()方法,并将执行任务的代码放入其中,call()将任务的执行结果作为返回值。适合于执行某种操作后,需要知道执行结果的情况。

 

无论是接收Runnable型参数,还是接收Callable型参数的submit()方法,都会返回一个Future(也是一个接口)类型的对象。该对象中包含了任务的执行情况以及结果。调用Future的boolean isDone()方法可以获知任务是否执行完毕;调用Object get()方法可以获得任务执行后的返回结果,如果此时任务还没有执行完,get()方法会保持等待,直到相应的任务执行完毕后,才会将结果返回。 

 

我们用下面的一个例子来演示Java5.0中线程池的使用: 

[java] view plaincopy 

import java.util.concurrent.*;  

public class ExecutorTest {  

    public static void main(String[] args) throws InterruptedException,  

            ExecutionException {  

        ExecutorService es = Executors.newSingleThreadExecutor();  

        Future fr = es.submit(new RunnableTest());// 提交任务  

        Future fc = es.submit(new CallableTest());// 提交任务  

        // 取得返回值并输出  

        System.out.println((String) fc.get());  

        // 检查任务是否执行完毕  

        if (fr.isDone()) {  

            System.out.println("执行完毕-RunnableTest.run()");  

        } else {  

            System.out.println("未执行完-RunnableTest.run()");  

        }  

        // 检查任务是否执行完毕  

        if (fc.isDone()) {  

            System.out.println("执行完毕-CallableTest.run()");  

        } else {  

            System.out.println("未执行完-CallableTest.run()");  

        }  

        // 停止线程池服务  

        es.shutdown();  

    }  

}  

class RunnableTest implements Runnable {  

    public void run() {  

        System.out.println("已经执行-RunnableTest.run()");  

    }  

}  

class CallableTest implements Callable {  

    public Object call() {  

        System.out.println("已经执行-CallableTest.call()");  

        return "返回值-CallableTest.call()";  

    }  

}  

 

运行结果: 

已经执行-RunnableTest.run()

已经执行-CallableTest.call()

返回值-CallableTest.call()

执行完毕-RunnableTest.run()

执行完毕-CallableTest.run()

 

使用完线程池之后,需要调用它的shutdown()方法停止服务,否则其中的所有线程都会保持运行,程序不会退出。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多