Android开发Android技术Android开发

线程池

2018-11-22  本文已影响87人  阴天吃鱼

在Android中,因为主线程的限制,执行一些耗时操作都必须在子线程中执行,使用子线程的时候多数都直接new一个,之后把执行的结果通过handler传输给主线程。
new的线程,我们没办法进行管理,只能在执行结束后去做相应的操作,假设第一个创建的线程未执行完毕,继续new多个线程,线程之间会进行竞争,可能会因为占有过多的资源而导致oom,死机或者线程被强制干掉。毕竟大量的创建和销毁都会消耗系统资源。

使用线程池的好处
.1.避免因为重复的创建和销毁而导致系统造成的开销。
.2.线程并发的管控,避免无限制的创建线程,有效的管理线程。
.3.提高系统的响应速度,避免等待线程的创建,直接放入队列进行操作。
.4.方便处理一些需要同步的操作。
.5.可控线程数量,提供定时等功能。

一、线程池介绍
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();
  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
        ThreadPoolExecutor threadPoolExecutor = 
new ThreadPoolExecutor(3,5,20,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());

threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                Log.e("MainActivity", "execute方式");
            }
        });
线程池执行流程

1.如果线程数量没有达到核心的线程数量,启动一个核心线程来执行任务。
2.如果线程池中的线程数量已经超过核心线程数,这时候任务就会被插入到任务队列中排队等待执行。
3.如果任务队列已满,任务无法插入到任务队列中。这个时候如果线程池中的线程数量没有达到线程池所设定的最大值,那么这时候就会启动一个非核心线程来执行任务。
4.如果线程池中的数量达到了所规定的最大值,那么就会拒绝执行此任务,这时候就会调用RejectedExecutionHandler中的rejectedExecution方法来通知调用者。

二、 四种线程池类型

都是直接或间接配置ThreadPoolExecutor 实现的常见线程池。

ExecutorService service = Executors.newFixedThreadPool(3);

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

设置的参数就是所能容纳的最大线程数,设置的线程为核心线程。线程池空闲状态的时候,线程不会被回收,如果所有线程都有任务执行,新任务会处于等待状态,直到有线程空闲出来。
由于newFixedThreadPool只有核心线程,并且这些线程都不会被回收,也就是 它能够更快速的响应外界请求 。从下面的newFixedThreadPool方法的实现可以看出,newFixedThreadPool只有核心线程,并且不存在超时机制,采用LinkedBlockingQueue,所以对于任务队列的大小也是没有限制。

 ExecutorService service = Executors.newCachedThreadPool();

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

newCachedThreadPool方法在这里我们可以看出它的核心线程数为0,线程最大数量为Integer.MAX_VALUE,这个值是一个很大的数,也可以理解为任意大、
当线程池有任务的时候,就会创建一个线程来执行任务,如果任务执行完毕后,线程闲置时间超过60秒的话就会被回收掉,所以说在60秒后线程池中不存在任何线程,这个时候是不占有任何资源的。

ScheduledExecutorService  service = Executors.newScheduledThreadPool(3);

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

它的核心线程数是固定的,对于非核心线程几乎可以说是没有限制的,并且当非核心线程处于限制状态的时候就会立即被回收。

创建一个可定时执行或周期执行任务的线程池:

ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
service.schedule(new Runnable() {
    public void run() {
        System.out.println("延迟三秒操作"+Thread.currentThread().getName());
    }
}, 3, TimeUnit.SECONDS);
service.scheduleAtFixedRate(new Runnable() {
    public void run() {
        System.out.println("延迟三秒后每隔2秒操作"+Thread.currentThread().getName());
    }
}, 3, 2, TimeUnit.SECONDS);

schedule(Runnable command, long delay, TimeUnit unit):延迟一定时间后执行Runnable任务;
schedule(Callable callable, long delay, TimeUnit unit):延迟一定时间后执行Callable任务;
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):延迟一定时间后,以间隔period时间的频率周期性地执行任务;
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit)::与scheduleAtFixedRate()方法很类似,但是不同的是scheduleWithFixedDelay()方法的周期时间间隔是以上一个任务执行结束到下一个任务开始执行的间隔,而scheduleAtFixedRate()方法的周期时间间隔是以上一个任务开始执行到下一个任务开始执行的间隔,也就是这一些任务系列的触发时间都是可预知的。

ExecutorService service = Executors.newSingleThreadExecutor();

  public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

newSingleThreadExecutor将所有的任务统一到一个线程中执行,所以在这个任务执行之间我
们不需要处理线程同步的问题。

总结

1.使用线程池需要看需求,如果是io密集任务,可以多设置线程来提高cpu的利用率,如果是cpu密集任务就是cpu个数+1的线程。
2.在需要统一管理线程的情况下,可以使用。
3.想避免过多的开销,可以使用。
4.想规定线程执行队列,可以使用。

上一篇下一篇

猜你喜欢

热点阅读