Android关于线程池的含义和使用

来源:互联网 发布:linux ping 不显示 编辑:程序博客网 时间:2024/05/29 15:14

介绍

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后创建线程后自动启动这些任务。


使用场景

线程的创建与销毁是一个耗时操作,如果在程序中反复创建和销毁线程,将会对程序的反应速度造成严重影响,有时甚至会Crash掉程序。因此在需要频繁使用线程的业务场景中,使用线程池是一个不错的选择。


使用好处

(1)重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
(2)能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
(3)能够对线程进行简单管理,并提供定时执行及指定间隔循环执行等功能。


何种情况不使用线程池

  • 需要使一个任务具有特定优先级 (如界面响应)
  • 长时间运行(并因此阻塞其他任务)的任务
  • 需要将线程放置到单线程单元中(线程池中的线程均处于多线程单元中)
  • 需要永久标识来标识和控制线程

创建方式

  • newCacheThreadPool()

如线程池长度超过处理需要,可灵活回收空闲线程,若无可回收则新建。
通常用于执行一些生存期很短的异步型任务。
注意,放的入CachedThreadPool线程不必担心其结束,超过TIMEOUT(缺省timeout是60s)不活动,其会自动被终止。

  • newFixedThreadPool()

定长线程池,可控制最大并发数,超过的线程会在队列中等待,直到当前线程中某个线程终止直接被移除池子。
和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP 或UDP IDLE机制之类的),所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器。

  • newScheduledThreadPool()

调度型线程池,支持定时及周期性任务执行。

  • newSingleThreadPool()

单线程化的线程池,任意时间 池中只能有一个线程。保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

ExecutorService

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

/** * 定长线程池 */ public static void Function() {    ExecutorService executorService = Executors.newFixedThreadPool(3);    for (int i = 0; i < 30; i++) {        final int index = i;        executorService.execute(new Runnable() {          @Override          public void run() {              try {                  System.out.println("index = " + index                          + "  thread count = " + Thread.activeCount());                  Thread.sleep(2000);              } catch (InterruptedException e) {                  // TODO Auto-generated catch block                  e.printStackTrace();              }          }      });  } }/** * 定长线程池,可做延时 */public static void Function() {    ScheduledExecutorService executorService = Executors            .newScheduledThreadPool(5);    executorService.schedule(new Runnable() {        @Override        public void run() {            System.out.println("delay 3 seconds" + "  thread count = "                    + Thread.activeCount());        }    }, 3, TimeUnit.SECONDS);}/** * 定期执行,可以用来做定时器 */public static void Function() {    ScheduledExecutorService executorService = Executors            .newScheduledThreadPool(3);    executorService.scheduleAtFixedRate(new Runnable() {        @Override        public void run() {            System.out                    .println("delay 1 seconds, and excute every 3 seconds"                            + "  thread count = " + Thread.activeCount());        }    }, 1, 3, TimeUnit.SECONDS);}

ExecutorService生命周期

线程池Executor是异步的执行任务,因此任何时刻不能够直接获取提交的任务的状态。这些任务有可能已经完成,也有可能正在执行或者还在排队等待执行。因此关闭线程池可能出现一下几种情况:

  • 平缓关闭:已经启动的任务全部执行完毕,同时不再接受新的任务
  • 立即关闭:取消所有正在执行和未执行的任务

shutdown方法:shutdown()是一个平缓的关闭过程,线程池停止接受新的任务,同时等待已经提交的任务执行完毕,包括那些进入队列还没有开始的任务,这时候线程池处于SHUTDOWN状态

shutdownNow方法:shutdownNow()是一个立即关闭过程,线程池停止接受新的任务,同时线程池取消所有执行的任务和已经进入队列但是还没有执行的任务,这时候线程池处于STOP状态。

awaitTermination方法:定时或者永久等待线程池关闭结束

isTerminated方法:检测线程池是否已经关闭


ExecutorService中execute和submit的区别

Executor接口只有一个方法execute。
submit方法在Executor中如下:

<T> Future<T> submit(Callable<T> task);<T> Future<T> submit(Runnable task , T result);Futrue<?> submit(Runnable task);

execute方法在Executor中如下:

void execute(Runnable command);

区别

  • executor方法没有返回值,也不会通过处理结果返回异常
  • submit方便Exception处理
  • 两者接收的参数不一样

举例如下:

public class RunnableTestMain {    public static void main(String[] args) {        ExecutorService pool = Executors.newFixedThreadPool(2);        /**         * execute(Runnable x) 没有返回值。可以执行任务,但无法判断任务是否成功完成。         */        pool.execute(new RunnableTest("Task1"));         /**         * submit(Runnable x) 返回一个future。可以用这个future来判断任务是否成功完成。请看下面:         */        Future future = pool.submit(new RunnableTest("Task2"));        try {            if(future.get()==null){//如果Future.get返回null,任务完成                System.out.println("任务完成");            }        } catch (InterruptedException e) {        } catch (ExecutionException e) {            //否则我们可以看看任务失败的原因是什么            System.out.println(e.getCause().getMessage());        }    }}public class RunnableTest implements Runnable {    private String taskName;    public RunnableTest(final String taskName) {        this.taskName = taskName;    }    @Override    public void run() {        System.out.println("Inside "+taskName);        throw new RuntimeException("RuntimeException from inside " + taskName);    }}

0 0