android 多线程 — 线程池基础

2019-04-20  本文已影响0人  前行的乌龟

线程池这个大家必会的把,就算咱是做 android 的,有现成的异步组件但是也保不齐什么时候得自己写个异步处理,再者面试时你要是不会线程池,面试官会把你虐出翔来


看妹子大家就有学习动力了

java 的4种自带线程池

线程池这玩必须复杂,Java 必须提供标准 API ,要不指不定能扭曲成啥样了,这不就有了Executors 这个类,通过 Executors 提供4种标准线程池:

1. FixedThreadPool

它是一种线程数量固定的线程池,它只有核心线程(不会被被回收,除非线程关闭),并且这些核心线程没有超时机制,任务队列也是没有大小限制(默认是 128),采用的是 LinkedBlockingQueue 阻塞队列

        val fixedThreadPool = Executors.newFixedThreadPool(3)
        fixedThreadPool.execute(object : Runnable {
            override fun run() {
                Thread.sleep(2000)
                Log.d("AA", "fixedThreadPool...run")
            }
        })
FixedThreadPool
2. SingleThreadExecutor

单线程线程池,关键得看怎么设计其中的阻塞队列,在 android 中的应用范围日挺广,android 这种移动客户端是没有什么并发要求的,到时这种按顺序执行的阻塞任务到时挺多,比如大多数 GUI 操作都是单线程的,数据库,日志,文件操作,应用批量安装,应用批量删除等不适合并发但可能 IO 阻塞性u以及影响 UI 线程响应的操作

        val fixedThreadPool = Executors.newSingleThreadExecutor()
        fixedThreadPool.execute(object : Runnable {
            override fun run() {
                Thread.sleep(2000)
                Log.d("AA", "fixedThreadPool...run")
            }
        })
SingleThreadExecutor
3. CachedThreadPool

它是一种线程数量不定的线程池,它只有非核心线程,并且其最大线程数为Integer.MAX_VALUE(因为 Integer.MAX_VALUE 的值很大,所以默认为线程数是为任意大),线程中的空闲线程都有超时机制,时长是60秒,超过60秒闲置线程就会被回收,采用的是 SynchronousQueue 这个阻塞队列

        val fixedThreadPool = Executors.newCachedThreadPool()
        fixedThreadPool.execute(object : Runnable {
            override fun run() {
                Thread.sleep(2000)
                Log.d("AA", "fixedThreadPool...run")
            }
        })
CachedThreadPool
4. ScheduledThreadPool

它的核心线程数量是固定的而非核心线程数是没有限制的,并且当非核心线程限制时会被立即回收,这类线程池主要用于执行定时任务和具有固定周期的重复任务。

        val fixedThreadPool = Executors.newScheduledThreadPool(3)
        fixedThreadPool.schedule(object : Runnable {
            override fun run() {
                Thread.sleep(2000)
                Log.d("AA", "fixedThreadPool...run")
            }
        },3,TimeUnit.SECONDS)

// 2000s 后执行 runnable
scheduledThreadPool.schedule(runnable,2000, TimeUnit.MILLISECONDS);
// 延迟 10ms 后,每隔 1000ms 执行一次 runnable
scheduledThreadPool.scheduleAtFixedRate(runnable,10,1000,TimeUnit.MILLISECONDS);
ScheduledThreadPool

线程池状态

关闭线程池

就是这2个 shutdown、shutdownNow API

线程池配置大小

一般需要根据任务的类型来配置线程池大小:


ThreadPoolExecutor

Android 中的线程池的概念来源于Java 中的 Executor,Executor 是一个接口,真正的线程池的实现为ThreadPoolExecutor,ThreadPoolExecutor 提供了一系列参数来配置线程池,通过不同的参数可以创建不同的线程池

实现关系如下:ThreadPoolExecute -> AbstractExecutorService -> ExecutorService -> Executor

通过 ThreadPoolExecutor 我们可以自己实现自己定制的线程池,这只是参数配置的不同,不过我是没碰到需要作到这一步的,想必也是后台开发才需要的吧

线程池的构造方法:

public ThreadPoolExecutor (int corePoolSize,
                           int maximumPoolSize,
                           long keepAliveTime,
                           TimeUnit unit,
                           BlockingQueue<Runnable workQueue>,
                           ThreadFactory threadFactory )

BlockingQueue

在线程池中 BlockingQueue 阻塞队列这个点相当重要了,甚至可以拿出来单独使用,队列概念也不难理解,利用数据结构存储数据,调节任务生产者和任务消费者之间的执行


这就是队列
队列大家也可以为栈,有2种处理任务的顺序:

阻塞队列应对的是个经典的生产者消费者场景,充当生产者和消费者之间的二道贩子(SynchronousQueue 这种队列除外),生产者和消费者不直接联系,生产者把任务交给阻塞队列,阻塞队列再去转手给下家消费者。一般阻塞队列都有大小的,当队列满了时,生产者再往队列里塞任务,那么就会阻塞生产者;当队列为空时,消费者没有任务就阻塞,核心线程是阻塞,非核心线程会回收,具体根据阻塞队列来

队列满阻塞添加任务的生产者 队列为空,阻塞取出任务的消费者线程
简单来看下队列的 API
目前有 7 种 BlockingQueue :

ArrayBlockingQueue 和 LinkedBlockingQueue 是两个最普通也是最常用的阻塞队列,一般情况下,在处理多线程间的生产者消费者问题,使用这两个类足以


小小的试试队列

我们 new 3个生产者,每个生产者添加 10 个任务,new 一个消费者,消费者线程 3 秒拿不到任务就结速线程,显示完事了

生产者

class Product(var name: String, var blockingQueue: BlockingDeque<String>) : Runnable {

    var tag: Boolean = true

    /**
     * 每隔 100 毫米添加一个任务进来
     */
    override fun run() {
        while (tag) {
            for (index in 1..10) {
                blockingQueue.offer("$name 添加的第$index 个任务")
                Thread.sleep(100)
            }
            tag = false
        }
    }
}

消费者

class Consumer(var name: String, var blockingQueue: BlockingDeque<String>) : Runnable {

    var tag: Boolean = true

    /**
     * 3 秒接受不到任务就结速线程
     */
    override fun run() {
        while (tag) {
            val work = blockingQueue.poll(3000, TimeUnit.SECONDS)
            Log.d("AA", "$name 处理任务 - $work")
            Thread.sleep(300)
            if (work == null) {
                tag = false
            }
        }
    }
}

执行代码

        btn_left.setOnClickListener {

            val linkedBlockingDeque = LinkedBlockingDeque<String>()
            val productAA = Product("Product_AA", linkedBlockingDeque)
            val productBB = Product("Product_BB", linkedBlockingDeque)
            val productCC = Product("Product_CC", linkedBlockingDeque)
            val consumerXX = Consumer("Consumer_XX", linkedBlockingDeque)

            val threadPool = Executors.newFixedThreadPool(4)
            threadPool.execute( productAA )
            threadPool.execute( productBB )
            threadPool.execute( productCC )
            threadPool.execute( consumerXX )
        }

参考资料:

上一篇 下一篇

猜你喜欢

热点阅读