Android: 线程相关知识点

快速切换到主线程更新UI的三种方法

  • Activity.runOnUiThread(Runnable)
    把更新UI的代码创建在Runnable中,并传给 Activity.runOnUiThread()如果当前线程是UI线程,那么会立即执行;反之,会调用UI线程handler.post()将其放入UI线程的消息队列中
new Thread(){
        public void run() {
        //此时在子线程
                ((MainActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                        //此时已经回到主线程,注意要强转到主线程的MainActivity
                        }
                });
        };
}.start();
  • View.post(Runnable)
    如果View已经attach到Window,直接调用UI线程的Handler发送Runnable到MessageQueue
    如果View还未attach到Window,将Runnable放入ViewRootImpl的RunQueue中,RunQueue会实现延迟执行Runnable任务,并且Runnable最终不会被加入到MessageQueue里,也不会被Looper执行,而是等到ViewRootImpl的下一个performTraversals时候,把RunQueue里的所有Runnable都拿出来并执行,接着清空RunQueue
mTextView.post(new Runnable() {
        @Override
        //可快速更新该view
        public void run() {
                mTextView.setText("xxx");
        //也可以更新其他view
        mIageView.setBackgroundResource(R.drawable.icon);
        }
});

还有View.postDelayed(Runnable, long),其中long表示延迟的毫秒数,示例如下。

//5秒倒计时跳转到下个页面
index=5;
mTextView.postDelayed(new Runnable() {
        @Override
        public void run() {
                mTextView.setText("" + index);
                index--;
                if (index == 0) {
                        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
                } else {
                        mTextView.postDelayed(this, 1000);
                }
        }
}, 1000);

c.Handler.post(Runnable)&Handler.post(Runnable,long)

//假设在子线程,需要获取主线程的Looper和Queue
new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
                //此时已经回到主线程
        }
});

当然还可以用AsyncTask、IntentService、HandlerThread,还有许多开源框架。

Thread阻塞方式:

  • sleep():
    进入休眠状态,但持有对象的锁旗标,休眠结束后,从阻塞状态——》就绪状态。

  • yield():
    进入休眠状态,也持有对象的锁旗标和sleep相似,但是不能控制时间,也有可能刚放弃运行就重新获取运行权。

  • wait():
    释放锁旗标,进入wait池,等到另一个线程对等待的对象调用notify()或notifyall()后,等待线程才会从wait池进入lock池(从一种阻塞状态进入另一种阻塞状态)。

  • synchornized未获取对象的锁旗标
    进入该对象lock池,等待锁旗标被归还,该对象的lock池中的线程才会获得锁旗标进入就绪状态。

  • Threa中的isAlive(),与线程状态有关。
    线程启动后,并且在run()方法没有结束前,isAlive返回true。
    所以如果返回false,就知道该线程处于刚被创建还尚未处于strat阶段,或者已处于dead状态。
    如果返回true,该线程就处于其生命周期中(运行或阻塞)。

线程状态流程图

java_thread_state.png
  • NEW:创建状态,线程创建之后,但是还未启动。
  • RUNNABLE:运行状态,处于运行状态的线程,但有可能处于等待状态,例如等待CPU、IO等。
  • WAITING:等待状态,一般是调用了wait()、join()、LockSupport.spark()等方法。
  • TIMED_WAITING:超时等待状态,也就是带时间的等待状态。一般是调用了wait(time)、join(time)、LockSupport.sparkNanos()、LockSupport.sparkUnit()等方法。
  • BLOCKED:阻塞状态,等待锁的释放,例如调用了synchronized增加了锁。
  • TERMINATED:终止状态,一般是线程完成任务后退出或者异常终止。

NEW、WAITING、TIMED_WAITING都比较好理解,我们重点说一说RUNNABLE运行态和BLOCKED阻塞态。

线程进入RUNNABLE运行态一般分为五种情况:

  • 线程调用sleep(time)后查出了休眠时间
  • 线程调用的阻塞IO已经返回,阻塞方法执行完毕
  • 线程成功的获取了资源锁
  • 线程正在等待某个通知,成功的获得了其他线程发出的通知
  • 线程处于挂起状态,然后调用了resume()恢复方法,解除了挂起。

线程进入BLOCKED阻塞态一般也分为五种情况:

  • 线程调用sleep()方法主动放弃占有的资源
  • 线程调用了阻塞式IO的方法,在该方法返回前,该线程被阻塞。
  • 线程视图获得一个资源锁,但是该资源锁正被其他线程锁持有。
  • 线程正在等待某个通知
  • 线程调度器调用suspend()方法将该线程挂起

我们再来看看和线程状态相关的一些方法。

  • sleep()方法让当前正在执行的线程在指定时间内暂停执行,正在执行的线程可以通过Thread.currentThread()方法获取。
  • yield()方法放弃线程持有的CPU资源,将其让给其他任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。
  • wait()方法是当前执行代码的线程进行等待,将当前线程放入预执行队列,并在wait()所在的代码处停止执行,知道接到通知或者被中断为止。该方法可以使得调用该方法的线程释放共享资源的锁, 然后从运行状态退出,进入等待队列,直到再次被唤醒。该方法只能在同步代码块里调用,否则会抛出IllegalMonitorStateException异常。wait(long millis)方法等待某一段时间内是否有线程对锁进行唤醒,如果超过了这个时间则自动唤醒。
  • notify()方法用来通知那些可能等待该对象的对象锁的其他线程,该方法可以随机唤醒等待队列中等同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态。
  • notifyAll()方法可以是所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态,一般会是优先级高的线程先执行,但是根据虚拟机的实现不同,也有可能是随机执行。
  • join()方法可以让调用它的线程正常执行完成后,再去执行该线程后面的代码,它具有让线程排队的作用。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 线程基本知识 什么是线程安全性?当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么可以认为这个类是线程安...
    Cheava阅读 995评论 0 1
  • 线程的状态Thread.yield()是使得线程从新变为就绪状态从新和其他就绪线程竞争cpu,有可能下次还是他运行...
    简书徐小耳阅读 132评论 0 0
  • 0.Android手机操作系统的四层架构? Applications , Application Framewor...
    lucas777阅读 7,676评论 0 16
  • 别人的总结不一定适合自己,所以尽量多做一些自己的总结,针对自己的薄弱点重点说明,适当的借鉴别人,少走一些弯路。最重...
    renkuo阅读 7,245评论 2 48
  • 年后上班的日子才是真的作息不规律! 晚上不睡,早晨不起! 真不像在家里那么正常,早睡早起,一日三餐家人定点叫我,不...
    赵小秋秋秋阅读 220评论 0 0