Android 并发工具类与线程池

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,若是能给各位看官带来一丝启发或者帮助,那真是极好的。java


前言

上一篇说到了Android并发编程中的 原子类与并发容器,那么本篇呢,继续上一篇记录一下Android并发编程中经常使用的一些工具类,以及面试必问知识点--线程池.面试

并发工具类

CountDownLatch(等待多线程完成)

CountDownLatch容许一个或多个线程等待其余线程完成操做。编程

当咱们须要用多个线程分解一些比较复杂任务时,这些任务一般符合下面两个规则:多线程

  1. 任务能够分解为多个相互独立的子任务
  2. 全部子任务的综合结果即为该任务的结果

用法:并发

public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
                c.countDown();
                System.out.println(2);
                c.countDown();
            }
        }).start();
        c.await();
        System.out.println("3");
    }
}

CountDownLatch的构造函数接收一个int类型的参数做为计数器,若是你想等待N个点完成,这里就传入N。当咱们调用CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await方法会阻塞当前线程,直到N变成零。框架

除了await()方法以外,也可使用另一个带指定时间的await方法——await(long time,TimeUnit unit),这个方法等待特定时间后,就会再也不阻塞当前线程。异步

总结来讲就是等待多个线程的完成,而后本身(调用await方法的线程)才运行.ide

CyclicBarrier(同步屏障)

同步屏障要作的事情是,让一个线程到达一个屏障(也能够叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,全部被屏障拦截的线程才会继续运行。
用法函数

public class CyclicBarrierTest {
    static CyclicBarrier c = new CyclicBarrier(2);
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
            try {
            c.await();
            } catch (Exception e) {
            }
            System.out.println(1);
            }
        }).start();
        try {
            c.await();
        } catch (Exception e) {
        }
        System.out.println(2);
    }
}

CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数
量,每一个线程调用await方法告诉CyclicBarrier我已经到达了屏障,而后当前线程被阻塞。当全部线程都到达了屏障时(即都调用了await方法)时,全部线程进行CPU竞争,由CPU调度运行.工具

Semaphore(控制线程数量)

Semaphore,信号量(令牌数).信号量这个概念跟咱们到一个很是火的饭店排队领号吃饭同样,因为饭店的容量是有限的,只能容纳N我的,前面N我的被叫到号进去用餐,其余的人只能等待,直到饭店中有人离开,才会继续叫号.

Semaphore的构造方法Semaphore(int permits)接受一个整型的数字,表示可用的许可证数量。在上面的例子中这个数字就是饭店中能容纳的人数.正在饭店内用餐的人表明正在运行的线程,在外面的等待的人表明阻塞的线程,吃完饭离开的人表明已经运行完毕的线程.

用法

public class SemaphoreTest {
    private static final int THREAD_COUNT = 30;
    private static ExecutorServicethreadPool = Executors
    .newFixedThreadPool(THREAD_COUNT);
    private static Semaphore s = new Semaphore(10);
        public static void main(String[] args) {
        for (inti = 0; i< THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();
                        System.out.println("save data");
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}

在代码中,虽然有30个线程在执行,可是只容许10个并发执行。Semaphore(10)表示容许10个线程获取许可证,也就是最大并发数是10。
Semaphore使用Semaphore的acquire()方法获取一个许可证,使用完以后调用release()方法归还许可证。还能够用tryAcquire()方法尝试获取许可证。

线程池

Java中的线程池是运用场景最多的并发框架,几乎全部须要异步或并发执行任务的程序
均可以使用线程池。在开发过程当中,合理地使用线程池可以带来3个好处。

  1. 下降资源消耗。经过重复利用已建立的线程下降线程建立和销毁形成的消耗。
  2. 提升响应速度。当任务到达时,任务能够不须要等到线程建立就能当即执行。
  3. 提升线程的可管理性。线程是稀缺资源,若是无限制地建立,不只会消耗系统资源,还会下降系统的稳定性,使用线程池能够进行统一分配、调优和监控。可是,要作到合理利用线程池,必须对其实现原理了如指掌。

Java中经常使用的线程池都是ThreadPoolExecutor不一样的配置产生的以符合不一样的场景.因此理解ThreadPoolExecutor相当重要.
下图是线程池的原理模型.

线程池模型

有了线程池的原理模型以后,咱们再看在Java库中是如何实现这个模型的,下面咱们来看ThreadPoolExecutor

ThreadPoolExecutor

图片描述

Java的经常使用线程池

FixedThreadPoolExecutor

FixedThreadPool被称为可重用固定线程数的线程池。

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

FixedThreadPoolExecutor是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了.当全部的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来.因为FixedThreadPool只有核心线程而且这些核心线程不会被回收,这意味着它可以更加快速的响应外界的请求.

SingleThreadExecutor详解

SingleThreadExecutor是使用单个worker线程的Executor.

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

SingleThreadPool内部只有一个核心线程,它确保全部的任务都在同一个线程中按顺序执行.

CachedThreadPool

CachedThreadPool是一个会根据须要建立新线程的线程池。

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

CachedThreadPool是一种线程数量不定的线程池,它只有非核心线程,而且其最大线程数Integer.MAX_VALUE是一个很大的数,实际上就至关于最大线程数能够任意大.当线程池中的线程都处于活动状态时,线程池会建立新的线程来处理新任务,不然就会利用空闲的线程来处理新任务.线程池中的空闲线程都有超时机制,60秒,超过60秒的的闲置线程就会被回收.
CachedThreadPoll比较适合执行大量的耗时较少的任务

ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它的核心线程数量是固定的,而非核心线程数是没有限制的,而且当非核心线程闲置时会被当即回收.它主要用来在给定的延迟以后运行任务,或者按期执行任务。


本篇总结

本篇呢,记录了一下并发编程中经常使用的一些工具类以及java或者Android面试中基本必问的只是点线程池.关于并发编程的记录暂告一段落.后面可能会出番外篇.最近也入职了新公司,忙着适应新公司的时候好像怠慢了本身的积累.后面尽可能会按照一个月一篇的速度更新博客,感谢关注个人粉丝.


此致,敬礼

相关文章
相关标签/搜索