Android并发编程

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写完了才能继续写。

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

3. 死锁问题

死锁的四个条件是:

  • 禁止抢占: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常用的方法

  会异常 返回是否成功 会阻塞 设定等待时间
入队列 add(e) offer(e) put(e) offer(e, timeout, unit)
出队列 remove() poll() take() poll(time, unit)
查看值 element() peek() none none

线程安全

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

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

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

线程安全的集合

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

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

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

时间: 2024-11-15 20:22:41

Android并发编程的相关文章

Android 并发编程:(一)基础知识 —— 架构和组件

本章节所有内容皆为原创,如需转载,请注明出处. http://blog.csdn.net/manoel/article/details/38462631 写在前面的话 很久没写博客了,一是因为自身水平有限,怕误人子弟:二是因为感觉没什么可写的:三是因为时间有限,要寻找工作.学习和生活之间的平衡. 最近一直在研究和梳理Android多线程编程的东西,希望能够把这些分享给大家. 想必做过Android应用开发的同学应该都会知道,多线程是一个特别"诡异"的地方.之所以称为"诡异&q

Android 并发编程:(一)基础知识 —— 1.2 程序的启动和终结

本章节所有内容皆为原创,如需转载,请注明出处. http://blog.csdn.net/manoel/article/details/38471825 Android是一个多用户,多任务的系统. 允许多个app在同一时刻执行,在多个程序之间切换并不会有明显的延迟. 多任务是由Linux内核负责处理的,而程序的运行基于Linux进程. Linux进程 Linux为每一个用户分配一个唯一的用户ID(User ID),用于区分不同的User. 因为权限的原因,每一个用户只能访问私有资源,没有用户(除

【Android 并发编程】线程间通信的三种基本方式

1. 使用管道流Pipes "管道"是java.io包的一部分.它是Java的特性,而不是Android特有的.一条"管道"为两个线程建立一个单向的通道.生产者负责写数据,消费者负责读取数据. 下面是一个使用管道流进行通信的例子. public class PipeExampleActivity extends Activity { private static final String TAG = "PipeExampleActivity";

《Qt on Android核心编程》介绍

<Qt on Android核心编程>终于尘埃落定,付梓印刷了. 封面 看看封面的效果吧,历经几版,最终就成了这个样子. 看下封皮: 这是立体版效果: 章节内容简介 第 1 章 欢迎来到Qt的世界,让我们看看Qt是什么,能给我们带来什么,又有谁在使用Qt.我们要约会的Qt on Android,它缘起何处,有着怎样曲折婉转的历史,如今的小模样能否让我们爱之如狂-- 第 2 章 当你遇见了合适的人,开始筹划第一次约会,又是兴奋又是惆怅,要不要买花,去哪里买礼物,穿什么衣服,洒什么香水,带什么应对

从一篇Blog看两个并发编程错误

发现公司支付宝接入的代码有点神奇,在网上搜索了下,找到原始版本.估计有不少人都是抄那份代码的. 原文在:http://blog.csdn.net/simdanfeg/article/details/9011603    Android支付接入(一):支付宝 但是代码里有两个明显的并发问题,尽管在Android下可能不会有问题. 下面摘抄一段: public class MobileSecurePayer { <strong>Integer lock = 0; </strong> /

Java并发编程从入门到精通 张振华.Jack --我的书

[当当.京东.天猫.亚马逊.新华书店等均有销售] 目 录 第一部分:线程并发基础 第1章 概念部分   1 1.1 CPU核心数.线程数 (主流cpu,线程数的大体情况说一下) 1 1.2 CPU时间片轮转机制 2 1.3 什么是进程和什么是线程 4 1.4 进程和线程的比较 5 1.5 什么是并行运行 7 1.6 什么是多并发运行 8 1.7 什么是吞吐量 9 1.8  多并发编程的意义及其好处和注意事项 10 1.9  分布式与并发运算关系 11 1.10 Linux和Window多并发可以

Android 异步编程

Android的线程和内存模型Android操作系统在boot后,会启动一个Zygote(受精卵)进程,Zygote进程负责创建大部分应用程序进程.Zygote进程启动 加载核心程序库和数据结构到内存后会创建一个Dalvik虚拟机(DVM)进程--SystemServer,此进程会包含大部分的系统服务(包括管理 Activity的服务ActivityManagerService),SystemServer初始化后,Zygote进程会侦听本地的socket 端口, 等待进一步的指令.当新的app被

Android多线程编程之线程池学习篇(一)

Android多线程编程之线程池学习篇(一) 一.前言 Android应用开发中多线程编程应用比较广泛,而应用比较多的是ThreadPoolExecutor,AsyncTask,IntentService,HandlerThread,AsyncTaskLoader等,为了更详细的分析每一种实现方式,将单独成篇分析.后续篇章中可能涉及到线程池的知识,特此本篇分析为何使用线程池,如何使用线程池以及线程池的使用原理. 二.Thread Pool基础 进程代表一个运行中的程序,一个运行中的Android

Java并发编程(六)阻塞队列

相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)ConcurrentHashMap的实现原理和源码分析 前言 在Android多线程(一)线程池这篇文章时,当我们要创建ThreadPoolExecutor的时候需要传进来一个类型为BlockingQueue的参数,它就是阻塞队列,在这一篇文章里我们会介绍阻塞队列的定义.种类.实现原理以及应用. 1.什么是阻塞队