并发与多线程开发核心技术

知识图谱

并发与多线程开发核心技术_第1张图片

  • Android Thread
    并发与多线程开发核心技术_第2张图片
    并发与多线程开发核心技术_第3张图片

线程的几种创建方式

  • 通过Thread类或Runnable接口创建
    并发与多线程开发核心技术_第4张图片
  • 通过Android 提供的AysncTask创建
    并发与多线程开发核心技术_第5张图片
    并发与多线程开发核心技术_第6张图片
    在这里插入图片描述
  • 通过HandlerThread
    并发与多线程开发核心技术_第7张图片
    并发与多线程开发核心技术_第8张图片
  • IntentService
    并发与多线程开发核心技术_第9张图片
  • ThreadPoolExecutor
    并发与多线程开发核心技术_第10张图片

线程的优先级

并发与多线程开发核心技术_第11张图片
并发与多线程开发核心技术_第12张图片

线程的几种状态与常用方法

并发与多线程开发核心技术_第13张图片
并发与多线程开发核心技术_第14张图片
并发与多线程开发核心技术_第15张图片

线程间通信

  • 主线程向子线程发送消息
    并发与多线程开发核心技术_第16张图片
    并发与多线程开发核心技术_第17张图片

Android多线程开发核心知识点

什么是线程并发安全

线程安全的本质是 能够让并发线程有序的运行(这个有序有可能是先来后到排队,有可能有人插队,但不管怎么着,同一时刻只能一个线程有权访问同步资源),线程执行的结果,能够对其他线程可见。

线程安全的几种分类
  • synchronized关键字
  • ReentrantLook锁
  • AtomicInteger。。。原子类
    并发与多线程开发核心技术_第18张图片
    并发与多线程开发核心技术_第19张图片
  • synchronized, ReentrantLock锁
    并发与多线程开发核心技术_第20张图片
  • 锁适合写操作多的场景,先加锁可以保证写操作时数据正确
  • 原子类适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。
如何保证线程安全
  • AtomicInteger原子包装类,CAS(Compare-And-Swap)实现无锁数据更新。自旋的设计能够有效避免线程因阻塞-唤醒带来的系统资源开销
  • 适用场景:多线程计数,原子操作,并发数量小的场景
    并发与多线程开发核心技术_第21张图片
  • volatile可见性修饰
    volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存重新读取该成员的值,而且,当成员变量值发生变化时,强迫将变化的值重新写入共享内存,不能解决非原子操作的线程安全性。性能也不及原子类高
    并发与多线程开发核心技术_第22张图片
  • 测试代码
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 一个用原子类修饰,一个用volatile修饰,在多线程的情况做自增,然后输出最后得值
 */
public class AtomicDemo {


    public static void main(String[] args) throws InterruptedException {
        final AtomicTask task = new AtomicTask();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    task.incrementVolatile();
                    task.incrementAtomic();
                }
            }
        };

        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("原子类的结果:" + task.atomicInteger.get());
        System.out.println("volatile修饰的结果:" + task.volatileCount);
    }

    static class AtomicTask {
        AtomicInteger atomicInteger = new AtomicInteger();
        volatile int volatileCount = 0;

        void incrementAtomic() {
            atomicInteger.getAndIncrement();
        }

        void incrementVolatile() {
            volatileCount++;
            //volatileCount = volatileCount + 1;
            //volatileCount = 10000;
        }
    }
}

  • synchronized
    锁Java对象,锁class对象,锁代码块
  • 锁方法,加在方法上,未获取到对象锁的其他线程都不可以访问该方法
    并发与多线程开发核心技术_第23张图片
  • 锁class对象。加在static方法上相当于给class对象加锁,哪怕是不同的Java对象实例,也需要排队执行
    并发与多线程开发核心技术_第24张图片
  • 锁代码块。未获取到对象锁的其他线程可以执行同步块之外的代码
    并发与多线程开发核心技术_第25张图片
  • synchronized的优势是什么?
    哪怕我们一个同步方法中出现了异常,那么jvm也能够为我们自动释放锁,能主动规避死锁。不需要开发者手动释放锁
  • synchronized劣势是什么?
    必须等到获取锁对象的线程执行完成,或者出现异常,才能释放掉。不能中途释放锁,不能中断一个正在试图获得锁的线程
    另外我们也不知道多个线程竞争锁的时候,获取锁成功与否,所以不够灵活
    每个锁仅有单一的条件(某个对象)不能设定超时
  • ReentrantLock悲观锁,可重入锁,公平锁,非公平锁
    基本用法
    并发与多线程开发核心技术_第26张图片
  • 测试代码
import java.util.concurrent.locks.ReentrantLock;

/**
 * 演示 多个线程去竞争锁的 用法
 */
public class ReentrantLockDemo {

    static class ReentrantLockTask {
        ReentrantLock reentrantLock = new ReentrantLock();

        void buyTicket() {
            String name = Thread.currentThread().getName();
            try {
                reentrantLock.lock();
                System.out.println(name + ":准备好了");
                Thread.sleep(100);
                System.out.println(name + ":买好了");

                reentrantLock.lock();
                System.out.println(name + ":又准备好了");
                Thread.sleep(100);
                System.out.println(name + ":又买好了");

                reentrantLock.lock();
                System.out.println(name + ":准备好了");
                Thread.sleep(100);
                System.out.println(name + ":又买好了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantLockTask task = new ReentrantLockTask();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.buyTicket();
            }
        };

        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }

}

  • 可重入锁,避免死锁
    并发与多线程开发核心技术_第27张图片
  • 公平锁与非公平锁
  • 公平锁,所有进入阻塞的线程排队一次均有机会执行
  • 默认非公平锁,允许线程插队,避免每一个线程都进入阻塞,再唤醒,性能高。因为线程可以插队,导致队列中可能会存在线程饿死的情况,一直得不到锁,一直得不到执行。
  • 传入false即为非公平锁
    在这里插入图片描述
import java.util.concurrent.locks.ReentrantLock;

/**
 * 演示  多个线程 去打印纸张,每个线程 打印张(ReentrantLock 公平锁,非公平锁)
 * 

* 公平锁:交易,比如先买票的人先进场 * 非公平锁:synchorinzed,场景比比皆是 */ public class ReentrantLockDemo2 { static class ReentrantLockTask { ReentrantLock lock = new ReentrantLock(false ); void print() { String name = Thread.currentThread().getName(); try { lock.lock(); //打印两次 System.out.println(name + "第一次打印"); Thread.sleep(1000); lock.unlock(); lock.lock(); System.out.println(name + "第二次打印"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public static void main(String[] args) { final ReentrantLockTask task = new ReentrantLockTask(); Runnable runnable = new Runnable() { @Override public void run() { task.print(); } }; for (int i = 0; i < 10; i++) { new Thread(runnable).start(); } } }

  • ReentrantLock进阶用法–Condition条件对象
    可使用它的await-singnal指定唤醒一个(组)线程。相比于wait-notify要么全部唤醒,要么只能唤醒一个,更加灵活可控

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 我们演示 生产者与消费者的场景,利用的是ReentrantLock condition 条件对象,能够指定唤醒某个线程去工作
 * 

*

* 生产者是:一个boss 去生产砖,砖的序列号为偶数,那么工人2去搬,奇数号让工人去去搬 *

* 消费者是两个工人,有砖搬就搬,没转搬就休息 */ public class ReentrantLockDemo3 { static class ReentrantLockTask { private Condition worker1Condition, worker2Condition; ReentrantLock lock = new ReentrantLock(true); volatile int flag = 0;//砖的序列号 public ReentrantLockTask() { worker1Condition = lock.newCondition(); worker2Condition = lock.newCondition(); } //工人1搬砖 void work1() { try { lock.lock(); if (flag == 0 || flag % 2 == 0) { System.out.println("worker1 无砖可搬,休息会"); worker1Condition.await(); } System.out.println("worker1 搬到的砖是:" + flag); flag = 0; } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } //工人2搬砖 void work2() { try { lock.lock(); if (flag == 0 || flag % 2 != 0) { System.out.println("worker2 无砖可搬,休息会"); worker2Condition.await(); } System.out.println("worker2 搬到的砖是:" + flag); flag = 0; } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } void boss() { try { lock.lock(); flag = new Random().nextInt(100); if (flag % 2 == 0) { worker2Condition.signal(); System.out.println("生产出来了砖,唤醒工人2去搬:" + flag); } else { worker1Condition.signal(); System.out.println("生产出来了砖,唤醒工人1去搬:" + flag); } } finally { lock.unlock(); } } public static void main(String[] args) { final ReentrantLockTask lockTask = new ReentrantLockTask(); new Thread(new Runnable() { @Override public void run() { while (true) { lockTask.work1(); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { lockTask.work2(); } } }).start(); for (int i = 0; i < 10; i++) { lockTask.boss(); } } } }

  • ReentrantReadWriteLock共享锁,排他锁
  • 共享锁,所有线程均可同时获得,并发量高,比如在线文档查看
  • 排他锁,统一时刻只有一个线程有权修改资源,比如在线文档编辑
    并发与多线程开发核心技术_第28张图片
  • 测试代码
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 利用ReentrantReadWriteLock  来实现 多人在线文档查看与编辑的功能
 */
public class ReentrantReadWriteLockDemo {

    static class ReentrantReadWriteLockTask {
        private final ReentrantReadWriteLock.ReadLock readLock;
        private final ReentrantReadWriteLock.WriteLock writeLock;
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

        ReentrantReadWriteLockTask() {
            readLock = lock.readLock();
            writeLock = lock.writeLock();
        }

        void read() {
            String name = Thread.currentThread().getName();
            try {
                readLock.lock();
                System.out.println("线程" + name + " 正在读取数据...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readLock.unlock();
                System.out.println("线程" + name + " 释放了读锁...");
            }
        }


        void write() {
            String name = Thread.currentThread().getName();
            try {
                writeLock.lock();
                System.out.println("线程" + name + " 正在写入数据...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                writeLock.unlock();
                System.out.println("线程" + name + " 释放了写锁...");
            }
        }

        public static void main(String[] args) {

            final ReentrantReadWriteLockTask task = new ReentrantReadWriteLockTask();


            for (int i = 0; i < 3; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        task.read();
                    }
                }).start();
            }


            for (int i = 0; i < 3; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        task.write();
                    }
                }).start();
            }
        }
    }
}

如何正确的使用锁&原子类
  • 减少持锁时间
    尽管锁在同一时间只能允许一个线程持有,其他想要占用锁的线程都得在临界区外等待锁的释放,这个等待的时间我们希望尽可能的短。
    并发与多线程开发核心技术_第29张图片
  • 锁分离
    读读,读写,写读,写写。只要有写锁进入才需要做同步处理,但是在大多数应用来说,读的场景要远远大于写的场景,因此一旦使用读写锁,在读多写少的场景中,就可以很好的提高系统的性能。
“ ” 读锁 写锁
读锁 可以访问 不可访问
写锁 不可访问 不可访问
  • 锁粗化
    多次加锁,释放锁合并成一次
    并发与多线程开发核心技术_第30张图片
    并发与多线程开发核心技术_第31张图片

深入理解Android线程池实现原理

为什么要引入线程池

在这里插入图片描述

Java中几种默认的线程池
  • 如何构建线程池
    并发与多线程开发核心技术_第32张图片

  • 线程池创建参数说明
    并发与多线程开发核心技术_第33张图片

  • JUC包下Executors提供的几种线程池
    并发与多线程开发核心技术_第34张图片

  • 线程池重要方法
    并发与多线程开发核心技术_第35张图片

  • 线程池状态流转
    并发与多线程开发核心技术_第36张图片

  • execute提交任务流程
    并发与多线程开发核心技术_第37张图片

  • 源码分析部分略过

实战:封装一个简洁易用的多线程操作框架
  • 需求分析
    设计一个全局通用的线程池组件-MyExecutor
    1. 支持任务优先级
    2. 支持线程暂停、恢复、关闭
    3. 支持异步任务结果回调
  • Coding实现
  • 线程池参数构造
    并发与多线程开发核心技术_第38张图片
  • 实现线程池中任务按优先级执行
    代码没截全,剩余部分应该能自己补出来
    并发与多线程开发核心技术_第39张图片
  • 实现线程池的暂停、恢复
    并发与多线程开发核心技术_第40张图片
  • 实现异步任务结果主动切换到主线程
    并发与多线程开发核心技术_第41张图片
  • 测试代码
import android.content.ContentValues.TAG
import android.os.Handler
import android.os.Looper
import androidx.annotation.IntRange
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
import kotlin.math.max

/**
 * 支持按任务的优先级去执行,
 * 支持线程池暂停.恢复(批量文件下载,上传) ,
 * 异步结果主动回调主线程
 * todo 线程池能力监控,耗时任务检测,定时,延迟,
 */
object HiExecutor {
    private const val TAG: String = "HiExecutor"
    private var isPaused: Boolean = false
    private var hiExecutor: ThreadPoolExecutor
    private var lock: ReentrantLock = ReentrantLock()
    private var pauseCondition: Condition
    private val mainHandler = Handler(Looper.getMainLooper());

    init {
        pauseCondition = lock.newCondition()

        val cpuCount = Runtime.getRuntime().availableProcessors()
        val corePoolSize = cpuCount + 1
        val maxPoolSize = cpuCount * 2 + 1
        val blockingQueue: PriorityBlockingQueue<out Runnable> = PriorityBlockingQueue()
        val keepAliveTime = 30L
        val unit = TimeUnit.SECONDS

        val seq = AtomicLong()
        val threadFactory = ThreadFactory {
            val thread = Thread(it)
            //hi-executor-0
            thread.name = "hi-executor-" + seq.getAndIncrement()
            return@ThreadFactory thread
        }

        hiExecutor = object : ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            keepAliveTime,
            unit,
            blockingQueue as BlockingQueue<Runnable>,
            threadFactory
        ) {
            override fun beforeExecute(t: Thread?, r: Runnable?) {
                if (isPaused) {
                    lock.lock()
                    try {
                        pauseCondition.await()
                    } finally {
                        lock.unlock()
                    }
                }
            }

            override fun afterExecute(r: Runnable?, t: Throwable?) {
                //监控线程池耗时任务,线程创建数量,正在运行的数量
                HiLog.e(TAG, "已执行完的任务的优先级是:" + (r as PriorityRunnable).priority)
            }
        }
    }

    fun execute(@IntRange(from = 0, to = 10) priority: Int = 0, runnable: Runnable) {
        hiExecutor.execute(PriorityRunnable(priority, runnable))
    }

    abstract class Callable<T> : Runnable {
        override fun run() {
            mainHandler.post { onPrepare() }

            val t: T? = onBackground()

            //移除所有消息.防止需要执行onCompleted了,onPrepare还没被执行,那就不需要执行了
            mainHandler.removeCallbacksAndMessages(null)
            mainHandler.post { onCompleted(t) }
        }

        open fun onPrepare() {
            //转菊花
        }

        abstract fun onBackground(): T?
        abstract fun onCompleted(t: T?)
    }

    class PriorityRunnable(val priority: Int, private val runnable: Runnable) : Runnable,
        Comparable<PriorityRunnable> {
        override fun compareTo(other: PriorityRunnable): Int {
            return if (this.priority < other.priority) 1 else if (this.priority > other.priority) -1 else 0
        }

        override fun run() {
            runnable.run()
        }

    }


    fun pause() {
        lock.lock()
        try {
            isPaused = true
            HiLog.e(TAG, "hiExecutor is paused")
        } finally {
            lock.unlock()
        }
    }

    fun resume() {
        lock.lock()
        try {
            isPaused = false
            pauseCondition.signalAll()
        } finally {
            lock.unlock()
        }
        HiLog.e(TAG, "hiExecutor is resumed")
    }
}

Kotlin协程机制

什么是协程
  • 场景1:异步回调嵌套
    并发与多线程开发核心技术_第42张图片

  • 协程的写法
    并发与多线程开发核心技术_第43张图片

  • 场景2:并发流程控制
    并发与多线程开发核心技术_第44张图片

  • 常规写法
    并发与多线程开发核心技术_第45张图片

  • 协程写法
    并发与多线程开发核心技术_第46张图片
    协程的目的是为了让多个任务之间更好的协作,解决异步回调嵌套。能够以同步的方式编排代码完成异步工作。将异步代码像同步代码一样直观。同时它也是一个并发流程控制的解决方案。
    协程主要是让原来使用“异步+回调”写出来的复杂代码,简化成看似同步写出来的方式,弱化了线程的概念(对线程的操作进一步抽象)。

协程的用法
  • 引入gradle依赖
    并发与多线程开发核心技术_第47张图片
  • 常用的创建协程的方法
    在这里插入图片描述
    并发与多线程开发核心技术_第48张图片
  • 测试代码
import android.util.Log
import kotlinx.coroutines.*


object CoroutineScene {

    private val TAG: String = "CoroutineScene"

    /**
     * 以此启动三个子线程, 并且同步的方式拿到他们的返回值,进而更新UI
     */
    fun startScene1() {
        GlobalScope.launch(Dispatchers.Unconfined) {
            Log.e(TAG, "coroutine is running")
            val result1 = request1()
            val result2 = request2(result1)
            val result3 = request3(result2)

            updateUI(result3)
        }

        Log.e(TAG, "coroutine has launched")
    }

    /**
     * 启动一个线程,先执行request1,完了之后,同时运行request2 和request3, 这俩并发都结束了才执行updateIU
     */
    fun startScene2() {

        GlobalScope.launch(Dispatchers.Main) {

            Log.e(TAG, "coroutine is running")

            val result1 = request1()
//           request2()
//           request3()

            val deferred2 = GlobalScope.async { request2(result1) }
            val deferred3 = GlobalScope.async { request3(result1) }

            // deferred2.await();
            //deferred3.await()
            updateUI(deferred2.await(), deferred3.await())
        }

        Log.e(TAG, "coroutine has started")
    }

    private fun updateUI(result2: String, result3: String) {
        Log.e(TAG, "updateui work on ${Thread.currentThread().name}")
        Log.e(TAG, "paramter:" + result3 + "---" + result2)
    }

    private fun updateUI(result3: String) {
        Log.e(TAG, "updateui work on ${Thread.currentThread().name}")
        Log.e(TAG, "paramter:" + result3)
    }

    //suspend关键字的作用--->
    //delay既然是IO异步任务,是如何做到延迟协程 中的代码向下执行的?
    suspend fun request1(): String {
        delay(2 * 1000)  //不会暂停线程,但会暂停当前所在的协程
        //Thread.sleep(2000)  让线程休眠

        Log.e(TAG, "request1 work on ${Thread.currentThread().name}")
        return "result from request1"
    }

    suspend fun request2(result1: String): String {
        delay(2 * 1000)

        Log.e(TAG, "request2 work on ${Thread.currentThread().name}")
        return "result from request2"
    }


    suspend fun request3(result2: String): String {
        delay(2 * 1000)

        Log.e(TAG, "request3 work on ${Thread.currentThread().name}")
        return "result from request3"
    }

}
协程挂起,恢复原理逆向剖析
  • 挂起函数
    被关键字suspend修饰的方法在编译阶段,编译器会修改方法的签名,包括返回值,修饰符,入参,方法实体。协程的挂起是靠挂起函数中实现的代码。

  • Kotlin代码
    并发与多线程开发核心技术_第49张图片

  • 反编译后生成的Java代码
    并发与多线程开发核心技术_第50张图片

  • 协程挂起与协程恢复
    在这里插入图片描述

  • 实例代码


import android.util.Log
import kotlinx.coroutines.delay

object CoroutineScene2 {

    private val TAG: String = "CoroutineScene2"

    suspend fun request1(): String {
        val request2 = request2();
        return "result from request1 " + request2;
    }

    suspend fun request2(): String {
        delay(2 * 1000)
        Log.e(TAG, "request2 completed")
        return "result from request2"
    }
}
  • 使用Java代码实现协程的suspend功能

import android.util.Log;

import org.jetbrains.annotations.NotNull;

import kotlin.coroutines.Continuation;
import kotlin.coroutines.CoroutineContext;
import kotlin.coroutines.intrinsics.IntrinsicsKt;
import kotlinx.coroutines.DelayKt;

/**
 * suspend fun request1(): String {
 * val request2 = request2();
 * return "result from request1 " + request2;
 * }
 * 

*

* suspend fun request2(): String { * delay(2 * 1000) * Log.e(TAG, "request2 completed") * return "result from request2" * } */ public class CoroutineScene2_decompiled { private static final String TAG = "CoroutineScene2"; public static final Object request1(Continuation preCallback) { ContinuationImpl request1Callback; if (!(preCallback instanceof ContinuationImpl) || (((ContinuationImpl) preCallback).label & Integer.MIN_VALUE) == 0) { request1Callback = new ContinuationImpl(preCallback) { @Override Object invokeSuspend(@NotNull Object resumeResult) { this.result = resumeResult; this.label |= Integer.MIN_VALUE; Log.e(TAG, "request1 has resumed"); return request1(this); } }; } else { request1Callback = (ContinuationImpl) preCallback; } switch (request1Callback.label) { case 0: { // Object delay = DelayKt.delay(2000, request1Callback); Object request2 = request2(request1Callback); if (request2 == IntrinsicsKt.getCOROUTINE_SUSPENDED()) { Log.e(TAG, "request1 has suspended"); return IntrinsicsKt.getCOROUTINE_SUSPENDED(); } } } Log.e(TAG, "request1 completed"); return "result from request1" + request1Callback.result; } public static final Object request2(Continuation preCallback) { ContinuationImpl request2Callback; if (!(preCallback instanceof ContinuationImpl) || (((ContinuationImpl) preCallback).label & Integer.MIN_VALUE) == 0) { request2Callback = new ContinuationImpl(preCallback) { @Override Object invokeSuspend(@NotNull Object resumeResult) { this.result = resumeResult; this.label |= Integer.MIN_VALUE; Log.e(TAG, "request2 has resumed"); return request2(this); } }; } else { request2Callback = (ContinuationImpl) preCallback; } switch (request2Callback.label) { case 0: { Object delay = DelayKt.delay(2000, request2Callback); if (delay == IntrinsicsKt.getCOROUTINE_SUSPENDED()) { Log.e(TAG, "request2 has suspended"); return IntrinsicsKt.getCOROUTINE_SUSPENDED(); } } } Log.e(TAG, "request2 completed"); return "result from request2"; } static abstract class ContinuationImpl<T> implements Continuation<T> { private Continuation preCallback; int label; Object result; public ContinuationImpl(Continuation preCallback) { this.preCallback = preCallback; } @NotNull @Override public CoroutineContext getContext() { return preCallback.getContext(); } @Override public void resumeWith(@NotNull Object resumeResult) { Object suspend = invokeSuspend(resumeResult); if (suspend == IntrinsicsKt.getCOROUTINE_SUSPENDED()) { return; } preCallback.resumeWith(suspend); } abstract Object invokeSuspend(@NotNull Object resumeResult); } }

协程回顾
  • 什么是协程
    协程是一种解决方案,是一种解决嵌套,并发,弱化线程概念的方案。能让多个任务之间更好的协作,能够以同步的方式编排代码完成异步工作。将异步代码写的像同步代码一样直观
  • 协程的启动
    根据创建协程指定的调度器 HandlerDispatcher,DefaultScheduler,UnconfinedDispatcher来执行任务,以决定协程中的代码块运行在那个线程上
  • 协程的挂起、恢复
    本质是方法的挂起、恢复。本质是return+Callback。
    用编译时的变换处理方法间的Callback,这样可以很直观地写顺序执行的异步代码。
  • 协程是线程框架么?
    协程的本质是编译时return+Callback。只不过在调度任务时提供了能够运行在IO线程的调度器。
  • 什么时候使用协程?
    多任务并发流程控制场景使用比较好,流程控制比较简单,不会涉及线程阻塞与唤醒,性能比Java并发控制手段高。
Kotlin协程应用

需求分析:如何让普通函数适配协程,成为“真正的挂起函数”。即让调用方以同步的方式拿到异步任务返回结果

import android.content.res.AssetManager
import android.util.Log
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.BufferedReader
import java.io.InputStreamReader
import java.lang.StringBuilder

/**
 * 演示以异步的方式 读取 asstes目录下的文件,并且适配协程的写法,让他真正的挂起函数
 *
 * 方便调用方 直接以同步的形式拿到返回值
 */
object CoroutineScene3 {
    suspend fun parseAssetsFile(assetManager: AssetManager, fileName: String): String {
       // suspendCoroutine<> {  }
        return suspendCancellableCoroutine { continuation ->
            Thread(Runnable {
                val inputStream = assetManager.open(fileName)
                val br = BufferedReader(InputStreamReader(inputStream))
                var line: String?
                var stringBuilder = StringBuilder()

//               while ((line=br.readLine())!=null){
//
//               }

                do {
                    line = br.readLine()
                    if (line != null) stringBuilder.append(line) else break
                } while (true)

                inputStream.close()
                br.close()

                Thread.sleep(2000)

                Log.e("coroutine", "parseassetsfile completed")
                continuation.resumeWith(Result.success(stringBuilder.toString()))
            }).start()
        }
    }
}

如何做多线程优化

线程池

并发与多线程开发核心技术_第51张图片

并发安全

并发与多线程开发核心技术_第52张图片
并发与多线程开发核心技术_第53张图片

  • 锁粗化
    并发与多线程开发核心技术_第54张图片
线程协作

并发与多线程开发核心技术_第55张图片

  • 实例代码
import java.util.Random;
import java.util.concurrent.CountDownLatch;

/**
* 演示一个 多人过山车的场景.
* 

* 我们假设有5人 去乘坐做过山车,----等待5人全部准备好,才能发车 */ public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { final CountDownLatch downLatch = new CountDownLatch(5); for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new Random().nextInt(4000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "准备好了"); downLatch.countDown(); } }).start(); } downLatch.await(); System.out.println("所有人都准备好了,准备发车..."); } }

并发与多线程开发核心技术_第56张图片

  • 示例代码
import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 * 演示 多人故宫游玩,但是同一时刻限流3人
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        final Semaphore semaphore = new Semaphore(3, true);
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        String name = Thread.currentThread().getName();
                        semaphore.acquire(2);

                        System.out.println(name + "获取到了许可证,进去游玩了");

                        Thread.sleep(new Random().nextInt(5000));

                        semaphore.release(2);

                        System.out.println(name + "归还了许可证");

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    }
}

协程

并发与多线程开发核心技术_第57张图片

你可能感兴趣的:(Android开发,Android,多线程,并发编程)