day3 线程

线程基础知识

线程状态

线程状态

线程可以有如下6中状态

  • New(新创建)
  • Runable(可运行)
  • Blocked(被阻塞)
  • Waiting(等待)
  • Timed waiting(计时等待)
  • Terminated(被终止)
    可调用用getState()方法获取当前状态

新创建线程

比如new Thread(r),该线程还没有开始运行,意味着它的状态为new。

可运行线程

一旦调用start方法,线程处于runable状态,一个可运行的线程可能正在运行也可能没有运行,这取决与操作系统给线程提供运行的时间。一旦一个线程开始运行,它不必始终都在运行,事实上,运行过程中,它可能会被中断,而中断的目的就是让其他线程获得运行机会,线程调度的细节依赖于操作系统提供的服务。抢占式调度系统给每一个可运行线程一个时间片来执行任务,当时间片用完,操作系统剥夺该线程的运行权,并给另一个线程运行机会。

被阻塞线程和等待线程

当线程被阻塞或等待线程时,它暂时不活动。它不运行任何代码且消耗最少的资源,知道线程调度器激活它。细节取决于它是怎样达到非活动状态的。

  • 当一个线程试图获取一个内部的对象锁,而该锁被其它线程所有,则该线程进入阻塞状态,当其它线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变成非阻塞状态。
  • 当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态。
    • 调用Object.wait方法或Thread.join方法
    • 等待java.util.concurrent库中的Lock或Condition时
  • 有几个方法有一个超时参数。调用它们导致线程进入计时等待状态。这一状态将一直保持到超时期满或者接收到适当的通知。带有超时期参数的方法有Thread.sleep和Object.wait,Thread.join,Lock.tryLock以及Condition.await的计时版。

被终止的线程

线程因如下两个原因之一而被终止:

  • 因为run方法正常退出而死亡
  • 因为一个没有捕获的异常终止了run方法而意外死亡

可以调用线程的stop方法杀死线程,该方法抛出一个ThreadDeath错误对象,由此杀死对象,但是,stop方法已经过时,不要再自己的代码中调用这个方法。

线程属性

包括:线程优先级,守护线程,线程组以及处理未捕获异常的处理器

线程优先级

每一个线程有一个优先级。默认情况下,一个线程继承它的父线程的优先级。可以用setPriority方法提高或降低任何一个线程的优先级,范围是MIN_PRIORITY(1)与MAX_PRIORITY(10)之间的任何值。NORM_PRIORITY被定义为5.
每当线程调度器有机会选择新线程时,它首先会选择具有较高优先级的线程。

守护线程

可以通过t.setDaemon(true)将线程转换为守护线程,守护线程的唯一用途是为其它线程提供服务。计时线程就是一个例子,它定时地发送“计时器滴答”信号给其它线程或清空过时的高速缓存项的线程。当只剩下守护线程时,虚拟机就退出了,由于如果只剩下守护线程,就没必要继续运行程序了。

未捕获异常处理器

线程的run方法不能抛出任何被检测的异常,但是,不被检测的异常会导致线程终止,在这种情况下,线程就死亡了。
不需要任何catch字句就可以来处理可被传播的异常,相反,就在线程死亡之前,异常被传递到一个用于未捕获异常的处理器,该处理器必须属于一个实现Thread.UncaughtExceptionHandler接口的类,这个接口只要一个方法:void uncaughtException(Thread t,Throwable e),可以用setUncaughtExceptionHandler为任何线程安装一个处理器,也可以用Thread类的setDefaultUncaughtExceptionHandler()为所有线程安装一个默认的处理器。
如果不安装默认的处理器,默认的处理器为空

同步

在大多数多线程应用中,两个或两个以上的线程需要共享对同一数据的存取。根据各线程访问数据的次序,可能会产生讹误的对象,这种情况成为竞争条件。如果并发的每个线程对共享数据的操作源于块不是原子操作,即它实际上编译后是多个虚拟机指令,比如说增值命令是由几条指令组成的,那么执行它们的线程可以在任何一条指令点上被中断。

锁对象

有两种机制防止代码块并发访问的干扰。

  • Java语言提供一个synchronized关键字,并且Java SE 5.0引入了ReentrantLock类。synchronized关键字自动提供一个锁以及相关的“条件”,对于大多数需要显示锁的情况很便利。
  • java.util.concurrent框架
myLock.lock();//a ReentrantLock object
try{
  critical section
}
finally{
    myLock.unlock();//make sure the lock is unlocked even if an exception is thrown
 }

这一结构确保任何时刻只有一个线程进入临界区,一旦一个线程封锁了对象,其它任何线程都无法通过lock语言。当其它线程调用lock时,他们被阻塞,知道第一个线程释放锁对象。

android 的消息机制

android的消息机制主要是指handler的运行机制,handler的运行需要底层的MessageQueue和Looper的支撑。MessageQueue是消息队列,内部储存了一组消息,以队列的形式对外提供插入和删除的工作,MessageQueue只是个消息的存储单元,它不能去处理消息,而Looper就可以以无限循环的形式去查找是否有新消息,如果有的话就处理,没有的话就一直等待着。Handler创建的时候会采用当前线程的Looper来构造消息循环系统。
具体介绍,这儿有一篇很好的文章,http://www.jianshu.com/p/d88e1af5100f

什么姿势开线程?

new thread()

new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();

优点:这种方式简单粗暴,是Android系统中开线程最简单的方式,也只能应用于最简单的场景,简单却伴随着不少的隐患。
缺点

  • 仅仅是启动了一个新的线程,没有任务的概念,不能做状态的管理
  • Runnable作为匿名内部类还持有了外部类的引用,先线程退出之前,改引用会一直存在,阻碍外部类对象被GC回收,在一段时间内造成内存泄漏。
  • 没有线程切换的接口,要传递处理结果到UI线程的话,需要些额外的线程切换代码。

ThreadPoolExecutor 线程池

优点:

  • 重用线程池中的线程, 避免因为线程的创建和销毁所带来的性能开销.
  • 有效控制线程池中的最大并发数,避免大量线程之间因为相互抢占系统资源而导致的阻塞现象.
  • 能够对线程进行简单的管理,可提供定时执行和按照指定时间间隔循环执行等功能.

AsyncTask

public class MyAsyncTask extends AsyncTask {

       @Override
       protected Object doInBackground(Object[] params) {
           return null;
       }

       @Override
       protected void onPreExecute() {
           super.onPreExecute();
       }

       @Override
       protected void onPostExecute(Object o) {
           super.onPostExecute(o);
       }
   }

优点:

  • 几处回调里可以有机会去中断任务,在任务状态的管理上较之Thread()方式更为灵活,AsyncTask的cancel()方法并不会终止任务的执行,开发者需要自己去检查cancel的状态值来决定是否中止任务。

  • 线程优先级为background,对UI线程的执行影响极小。
    缺点:

  • AsyncTask也有隐式的持有外部类对象引用的问题,需要特别注意防止出现意外的内存泄漏。

  • AsyncTask由于在不同的系统版本上串行与并行的执行行为不一致,被不少开发者所诟病,这确实是硬伤,绝大部分的多线程场景都需要明确任务是串行还是并行。

HandlerThread

HandlerThread将Handler,Thread,Looper,MessageQueue几个概念相结合。Handler是线程对外的接口,所有新的message或者runnable都通过handler post到工作线程。Looper在MessageQueue取到新的任务就切换到工作线程去执行。不同的post方法可以让我们对任务做精细的控制,什么时候执行,执行的顺序都可以控制。HandlerThread最大的优势在于引入MessageQueue概念,可以进行多任务队列管理。

特点:

  • HandlerThread背后只有一个线程,任务是串行执行的。
  • HandlerThread产生的线程会一直存活,Looper会在该线程中持续的检查MessageQueue。
  • 较之Thread,AsyncTask需要写更多的代码,但在实用性,灵活性,安全性上都有更好的表现。

IntentService

它相当于是Service和HandlerThread的结合体,就是在Service里面开了个线程,只是在所有的Message处理完毕之后,工作线程会自动结束,然后Service也会销毁。

Rxjava

观察者与被观察者模式,两个角色可以在不同的线程执行。

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

推荐阅读更多精彩内容