多线程编程

一个Android应用在创建的时候会开启一个线程,我们称为主线程或者UI线程,如果我们想要访问网络或者数据库等耗时操作时,都会开启一个子线程。

线程的状态

New 新创建状态
Runnable 可运行状态
Blocked 阻塞状态
Waiting 等待状态
Timed waiting 超时等待状态
Terminal 终止状态
线程创建后,调用Thread的start方法,开始进入运行状态,当线程执行wait方法后,线程进入等待状态,进入等待状态的线程需要其他线程通知才能返回运行状态。超时等待相当于在等待状态加上了时间限制,如果超过时间限制,则线程返回运行状态。当线程调用同步方法时,如果线程没有获得锁则进入阻塞状态,当阻塞状态的线程获取到锁时则重新回到运行状态。当线程执行完毕或者遇到意外异常终止时,都会进入终止状态。

创建线程

1.继承Thread类,重写run方法
调用start方法并不是立即地执行多线程的代码,而是使线程变为可运行态,什么时候运行多线程代码是由系统决定的。
2.实现Runnable接口,并实现该接口的run方法
3.实现Callable接口,重写call方法
可以带返回值,可以抛出异常

中断

当一个线程调用interrupt方法时,线程的中断标识位将被置位(中断标识位为true),线程会不时地检测这个中断标识位,以判断线程是否应该被中断。通过Thread.currentThread().isInterrupted()来判断线程是否被置位。

同步

重入锁与条件对象
重入锁ReentrantLock就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。

Lock mLock = new ReentrantLock();
mLock.lock();
try{
      ...
}
finally{
    mLock.unlock();
}

这一结构确保任何时刻只有一个线程进入临界区,临界区就是在同一时刻只能有一个任务访问的代码区;
进入临界区时,却发现在某一条件满足之后,它才能执行。这时可以使用一个条件对象来管理那些已经获得了一个锁但是不能做有用工作的线程。
一个锁对象可以有多个相关的条件对象,可以用newCondition方法获得一个条件对象,我们得到条件对象后条用await方法,当前线程就被阻塞了并放弃了锁。

同步方法

Java中的每一个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法;
内部对象锁只有一个相关条件,wait方法将一个线程添加到等待集合中,notifyAll或者notify方法解除等待线程的阻塞状态。

同步代码块
synchronized(obj){
}
volatile

volatile关键字为实例域的同步访问提供了免锁的机制。
Java内存模型定义了线程和主存之间的抽象关系:线程之间的共享变量存储在主存中,每个线程都有一个私有的本地内存,本地内存中存储了线程共享变量的副本。
并发编程中的3个特性:
1.原子性
对基本数据类型变量的读取和赋值操作时原子性操作。
一个语句包含有多个操作时,就不是原子性操作,只有简单地读取和赋值才是原子性操作。
2.可见性
可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的;
当一个共享变量被volatile修饰时,它会保证修改的值立即被更新到主存,所以对其他线程时可见的。
3.有序性
让线程顺序执行同步代码。



当一个共享变量被volatile修饰之后,一个线程修改了变量的值时,变量的新值对其他线程时立即可见的。
volatile不保证原子性
eg.自增操作是不具备原子性的,它包括读取变量的原始值,进行加1,写入工作内存。
volatile保证有序性
运用场景:
1.状态标志
2.双重检查模式(DCL)

public class Singleton{
    private volatile static Singleton instance = null;
    public static Singleton getInstance(){
        if(instance==null) {
            synchronized(this){
                if(instance==null) {
                    instance = new Singleton();
                }
            }
        }
    }
}
//getInstance方法中对Singleton进行了两次判空,第一次是为了不必要的同步,第二次是只有在Singleton等于null的情况下才创建实例。
阻塞队列BlockingQueue

阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
阻塞场景:
1.当队列中没有数据的情况,消费者端的所有线程都会被自动阻塞(挂起),直到有数据放入队列。
2.当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒。
Java中的阻塞队列:
ArrayBlockingQueue:用数组实现的有界阻塞队列,FIFO,是维护一个Object类型的数组
LinkedBlockingQueue:基于链表的阻塞队列
PriorityBlockingQueue
DelayQueue
SynchronousQueue
LinkedTransferQueue
LinkedBlockingDeque

线程池

通过ThreadPoolExecutor来创建一个线程池
构造方法:

public ThreadPoolExecutor(
    int corePoolSize,//核心线程数
    int maximumPoolSize,//线程池允许创建的最大线程数,当活动线程数达到这个数值后,后续的新任务会被阻塞
    long keepAliveTime,//非核心线程闲置的超时时长,超过这个时长,非核心线程就会被回收,当ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,keepAliveTime同样会作用与核心线程
    TimeUnit unit,//keepAliveTime参数的时间单位
    BlockingQueue<Runnable> workQueue,//线程池中的任务队列
    ThreadFactory threadFactory,//线程工厂
    RejectedExecutionHandler handler//饱和策略
){}

线程池的处理流程:
1.如果线程池中的线程数量未达到核心线程的数量,那么直接启动一个核心线程来执行任务。
2.如果线程池中的线程数量达到或则超过核心线程的数量,那么任务会被插入到任务队列中排队等待执行。
3.如果由于任务队列已满,无法将任务插入到任务队列中,这个时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。
4.如果线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution方法来通知调用者。

线程池种类:

1.FixedThreadPool
通过Executors的newFixedThreadPool方法来创建。它是一种线程数量固定的线程池;FixedThreadPool中只有核心线程并且这些核心线程没有超时机制,另外任务队列没有大小限制。
2.CachedThreadPool:
它是一种线程数量不定的线程池,它只有非核心线程,并且其最大线程数为Integer.MAX_VALUE。
比较合适执行大量的耗时较少的任务。
3.SingleThreadExecutor 单个工作线程的线程池
只有一个核心线程,它确保所有的任务在同一个线程中顺序执行
4.ScheduledThreadPool 能实现定时和周期性任务的线程池

《Android进阶之光》多线程编程
《Android艺术探讨》Android的线程和线程池
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容