文章目录
  1. 1. 并发
  2. 2. 什么是并发
  3. 3. 并发的风险
  4. 4. 线程篇
  5. 5. 进程是什么
  6. 6. 进程与线程的关系
  7. 7. 单线程
  • 多线程
  • 多线程并发过程中会遇到的问题
    1. 1. 线程如何去用
    2. 2. 线程的优先级
  • 线程池
    1. 1. 队列
  • 线程安全
    1. 1.
    2. 2. 感谢
  • 转自Abner_泥阿布

    Android的并发编程,即多线程开发,而Android的多线程开发模型也是源于Java中的多线程模型。
    所以本篇也会先讲一些Java中的多线程理念,再讲解具体涉及的类,最后深入Android中的并发场景和实践。

    并发

    什么是并发

    举个很简单的栗子,当你一边在撸撸撸,一边在看小视频,同时在做两件事,这就是并发。

    咳,年轻人节制啊。

    并发的好处

    提高资源利用率

    当一个任务并没有完全占用系统资源,就可以利用并发来提高资源利用率,同时也能更快地完成任务。

    当你的右手在干些什么的时候,左手是不是在没事做呢?那就也用起来呗。
    (某次聚会,一名骑马的汉子说自己左右互搏(lu)特厉害)。

    在程序任务上更加精简

    就拿上一个栗子来说,左手做什么,右手做什么,任务明确分配好,又能同时进行,既提高了效率,逻辑又清晰。

    更好的响应程序

    这个拿Android客户端举个栗子,上传图片时,当前界面还是正常运转没有卡死,图片也正常上传,既保证了界面被响应,又保证图片可以上传。

    并发的风险

    ### 并发的代价

    需要占用更多的资源。
    设计好一个并发程序并不容易。
    并发的资源交互问题复杂。
    并发的隐患

    滥用资源导致系统不稳定
    结果与预期不符
    出现BUG难以排查

    线程篇

    进程是什么

    就拿Android中的App来说,一般来说一个app就是一个进程,(除了特殊的手段开启了多个进程,这里不深入这个话题,就是一个一对多的关系)。

    线程是什么

    进程只是一个程序、任务的统称,但是却不能执行任务,真正执行任务的是线程,所以线程是由进程创建的,一个进程可以创建多个线程。

    线程可以调度资源等等,在这里只需要了解大致的概念就好,如果要深入可以学习一下操作系统。

    进程与线程的关系

    人脑就相当于是CPU,想做一件事的时候,这个任务就是一个进程了,需要运用手脚等器官去完成这个任务,而手脚器官就可以理解成一个个线程,去做了不同的事,从而完成任务。

    单线程

    还是用Android举栗子,当你在手机上操作的时候,这个被称之为UI线程(之后会详解)。而一个最基本的app,不需要复杂的功能时,就只有一个UI线程和我们交互,那么这个app就是个单线程的。一般的程序面向用户的线程就是UI线程,也称之为主线程,单线程程序,其实就是只有一个主线程的程序。

    多线程

    多个进程可以算是并发,但是我们所说的并发场景,大部分是在一个进程中的,而并发就是由线程完成的,多个线程同时执行任务,就称之为并发。

    以下为多线程工作示意图:

    多线程并发过程中会遇到的问题

    1. 资源共享

    A线程要写文件C,B线程也要写文件C,这个时候就好像你拿着两只笔同时往纸上写东西,写出来的是什么自己也不知道。

    这个时候我们需要一个类似于锁的东西,当C被A在写的时候,B不能写,B要等A写完了才能继续写。

    至于这个锁到底是什么会在后面继续讲到。

    1. 死锁问题

    死锁的四个条件是:

    • 禁止抢占:no preemption
    • 持有和等待:hold and wait
    • 互斥:mutual exclusion
    • 循环等待:circular waiting

    预防死锁就是至少破坏这四个条件其中一项,即破坏“禁止抢占”、破坏“持有等待”、破坏“资源互斥”和破坏“循环等待”。

    举个例子:

    A在B那边割包皮,B把A割坏了,A占着B的床位,要B赔钱,B要A让出床位才给钱。双方僵持不下。

    线程如何去用

    在Java中,线程通常就是指Thread这个类,或者实现了Runnable的类,其实Thread这个类也是实现了Runnable接口的,可以看一下Runnable接口的代码:

    里面就是一个run方法需要被实现。

    再看一下Thread类的声明:

    确实是一个实现了Runnable的类。

    那么Thread类中拥有start()方法,和run()方法,下面用run()方法直接调用
    得到信息:

    发现其实和外面的线程是在同一个线程上。

    而调用start()方法得到的信息是:

    发现线程名不一样了,用start会开启一个新的线程,而run还是在当前线程执行。

    另外在Java1.5之后,还有Callable、Future和FutureTask,在这里就不详细介绍,还有线程的wait、
    yield、sleep等在下一章会一起详细介绍。

    线程的优先级

    在Java中,线程的优先级有1~10,而默认的是5。1最低,10最高。在Thread类中有三个常量:

    • MIN_PRIORITY = 1
    • NORM_PRIORITY = 5
    • MAX_PRIORITY = 10

    在同一个线程池中的线程优先级是相同的。

    JVM会根据线程的优先级去抢先调度,然而线程的优先级只能保证抢占资源的概率较大,并不能保障线程的执行顺序,所以不能过于依赖设置线程的优先级。

    线程池

    频繁地创建和销毁线程会导致性能大幅度降低,这肯定不是你希望的。

    线程池的出现,就是为了解决这个问题,根据java中提供不同的线程池机制,有效地提高资源利用率。

    直接在代码中创建Thread、Runnable去start或者run容易出现不可预测的问题,在java1.5开始,引入了java.util.concurrent包,其中有个并发的框架:Executor,使用ExecutorService替代直接操作线程类,而Executors是用来创建线程池的,内部提供了很多静态方法去创建你想要的线程池,不需要你再手动去创建实现。
    看一下关于Executor中的类和接口的大致的成员与关系:

    关于这些类如何使用,以及有什么特性,下一章会作介绍。

    队列

    在java中提到队列肯定会想起Queue,而线程队列用的是BlockingQueue,这是个接口,在concurrent包中有好几个类实现了这个接口。

    介绍一下BlockingQueue常用的方法

    线程安全

    在前面讲过死锁,死锁是由于使用不当引起的一种现象,而这里的锁是人工干预的,让并发按照你的意思走。

    在java中的锁有synchonrized、Lock。锁的出现主要是为了解决线程安全问题。

    关于线程的状态会在下一章讲锁的机制时候再讲,因为线程的状态会影响到锁。

    线程安全的集合

    因为多线程访问资源可能会造成数据不一致或者数据污染,而某些集合会用一些锁或者同步机制做了处理。

    线程安全的集合有:HashTable、SynchronizedCollection、ConcurrentHashMap、Vector等。

    线程安不安全的首要前提是在多线程访问同一个对象的情况下。

    感谢

    《Java并发编程实践》

    《Thinking in Java》

    baoyongzhang(鲍老师)


    未经许可不得转载,转载请注明zilianliuxue的blog,本人保留所有版权。

    文章目录
    1. 1. 并发
    2. 2. 什么是并发
    3. 3. 并发的风险
    4. 4. 线程篇
    5. 5. 进程是什么
    6. 6. 进程与线程的关系
    7. 7. 单线程
  • 多线程
  • 多线程并发过程中会遇到的问题
    1. 1. 线程如何去用
    2. 2. 线程的优先级
  • 线程池
    1. 1. 队列
  • 线程安全
    1. 1.
    2. 2. 感谢