android執行緒管理二(Thread)
前言
一 結構關係
publicclassThreadimplementsRunnable{...... }很顯然Thread繼承了Runnable。 Runnable原始碼如下:
public interface Runnable { public abstract void run(); }Runnable很簡單,它是一個介面,只用一個方法run();
二 建構函式
Thread#構造方法:public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } public Thread說明,這只是部分構造方法,從這些構造方法中可以看出都是呼叫了函式init。 Thread#init:(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } public Thread(ThreadGroup group, Runnable target) { init(group, target, "Thread-" + nextThreadNum(), 0); } ......
/** * 很明顯這個方法是用來初始化執行緒的 * @param g 執行緒組 你建立的執行緒最終會被新增到這個執行緒組中* @param target Runnable型別 用於回撥 * @param name 即將建立的執行緒的名字 * @param stackSize 即將建立的執行緒的棧的大小,如果是0,表明忽略此引數 */privatevoidinit(ThreadGroup g, Runnable target, String name,long stackSize){//呼叫native層的currentThread函式獲取當前環境所在的執行緒,例如在Activity中,你獲取的將是UI執行緒 Thread parent = currentThread();if(g ==null){//執行緒parent所屬的執行緒組 g = parent.getThreadGroup();}//函式1 後臺執行緒數加1 g.addUnstarted();//儲存執行緒組this.group= g;//儲存 Runnable型別 用於回撥this.target= target;//parent獲取執行緒優先權1-10this.priority= parent.getPriority();//是否是後臺執行緒this.daemon= parent.isDaemon();//設定執行緒的名字 setName(name);//函式2 init2(parent);/* Stash the specified stack size in case the VM cares */this.stackSize= stackSize;//建立執行緒Id,執行緒的唯一標識 tid = nextThreadID();}
1 addUnstarted
Thread#addUnstarted:void addUnstarted() { synchronized(this) { if (destroyed) { throw new IllegalThreadStateException(); } nUnstartedThreads++; } }註釋已經說的很清楚了:
/**大致意思就是:把thread group 中的即將啟動的執行緒數加一,這樣可以在該執行緒沒有啟動的情況,避免被銷燬。
* Increments the count of unstarted threads in the thread group.
* Unstarted threads are not added to the thread group so that they
* can be collected if they are never started, but they must be
* counted so that daemon thread groups with unstarted threads in
* them are not destroyed.
*/
2 int2
Thread#int2:private void init2(Thread parent) { //獲取執行緒parent的類載入器 ClassLoader型別 this.contextClassLoader = parent.getContextClassLoader(); this.inheritedAccessControlContext = AccessController.getContext(); if (parent.inheritableThreadLocals != null) { //給當前執行緒建立ThreadLocalMap物件,並且繼承parent的ThreadLocalMap中的資料 this.inheritableThreadLocals = ThreadLocal.createInheritedMap( parent.inheritableThreadLocals); } }說明,這裡有兩點需要注意下: a :類載入器即ClassLoader,那麼什麼是類載入器?一個完整的Java程式可能由幾個.class檔案組成,程式在執行的過程中並不是一下子把所有的.class檔案放置記憶體中,而是通過類載入器把需要的.class檔案載入到記憶體中,進而其他的.class檔案可訪問到這個該.class檔案。想了解更多關於ClassLoader,可以參考這篇《深入分析Java 類載入器》文章。 b:ThreadLocalMap 它是ThreadLocal的內部類,每個Thread都一個ThreadLocalMap,其結構是Map型別,key儲存的是當前執行緒的ThreadLocal物件,value儲存的是Object型別的變數,其作用使用ThreadLocal宣告一個變數時,ThreadLocal會為每個執行緒建立這個變數的副本,當執行緒對這個變數進行操作時,互相之間不受影響,在一定程度上解決多執行緒不安全的問題。關於ThreadLocal以後會詳細介紹。
三 生命週期
1執行緒狀態
public enum State { NEW,//被例項化之後,但還沒有呼叫start啟動 RUNNABLE,//呼叫了start函式之後就處於Runnable狀態 BLOCKED,//呼叫join()、sleep()、wait()使執行緒處於Blocked狀態 WAITING,// TIMED_WAITING,// TERMINATED;// }
(1) new
new也稱為新執行緒狀態,通過new關鍵字例項化一個Thread物件就生成一個新執行緒。當執行緒處於"新執行緒"狀態時,僅僅是一個空執行緒物件,它還沒有分配到系統資源。因此只能啟動或終止它。任何其他操作都會引發異常。例如,一個執行緒呼叫了new方法之後,並在呼叫start方法之前的處於新執行緒狀態,可以呼叫start和stop方法。(2)Runnable
Runnable也稱為可執行狀態,通過start方法後使執行緒處於該狀態,此時執行緒獲取了支援其執行的資源,並排程其run方法,這個狀態不能想當然的認為是執行狀態,因為這時的執行緒並不總是一直佔用處理機,它也有可能不在執行,這是因為還有優先順序和排程問題。特別是對於只有一個處理機的PC而言,任何時刻只能有一個處於可執行狀態的執行緒佔用處理機。Java通過排程來實現多執行緒對處理機的共享。 (3)NOT Runnable NOT Runnable也稱為阻塞狀態,當以下事件發生時,執行緒處於該狀態: a:呼叫supped、sleep方法 b:呼叫wait方法等待條件變數 c:執行緒處於I/O請求的等待(4)Dead
Dead也稱為死亡狀態,run方法執行完畢、其他執行緒呼叫該執行緒的stop方法、異常終止都會使執行緒處理該狀態。2 執行緒的操作:
派生:執行緒在程序內派生出來,它即可由程序派生,也可由執行緒派生。 阻塞(Block):如果一個執行緒在執行過程中需要等待某個事件發生,則被阻塞。 啟用(unblock):如果阻塞執行緒的事件發生,則該執行緒被啟用並進入就緒佇列。 排程(schedule):選擇一個就緒執行緒進入執行狀態。 結束(Finish):如果一個執行緒執行結束,它的暫存器上下文以及堆疊內容等將被釋放。好,接下來借用網友一幅圖加於說明:
四 函式分析
1 start函式分析
一個執行緒啟動呼叫的是start函式,下面我們看下它的原始碼: Thread#start:public synchronized void start() { /** *threadStatus ==0,說明該執行緒狀態為"NEW",還沒有啟動過,一個執行緒只能啟動一次,否則丟擲異常。 */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* 把當前執行緒新增到執行緒組中 */ group.add(this); started = false; try { //呼叫native層函式建立執行緒,native層的原始碼未找到先不討論它 nativeCreate(this, stackSize, daemon); started = true; } finally { ...... } }說明,這個方法主要兩個作用: a:把執行緒新增到執行緒組中 b:呼叫native層的nativeCreate函式完成執行緒的建立。
2 interrupt函式分析
Thread#interrupt:public void interrupt() { if (this != Thread.currentThread()) checkAccess(); //blockerLock synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { nativeInterrupt(); b.interrupt(this); return; } }//呼叫native層函式完成執行緒中斷 nativeInterrupt(); }說明,在Java中“中斷”執行緒是通過interrupt()方法來實現的,之所以加引號,是因為interrupt()並不中斷正在執行的執行緒,只是向執行緒傳送一箇中斷請求,具體行為依賴於執行緒的狀態,如下: a:如果執行緒處於阻塞狀態,即執行緒被Object.wait()、Thread.join()或 Thread.sleep()阻塞,呼叫interrupt()方法,將接收到InterruptedException異常,中斷狀態被清除,結束阻塞狀態; b:如果執行緒在進行I/O操作(java.nio.channels.InterruptibleChannel)時被阻塞,那麼執行緒將收到java.nio.channels.ClosedByInterruptException異常,通道被關閉,結束阻塞狀態; c:如果執行緒被阻塞在java.nio.channels.Selector中,那麼中斷狀態會被置位並返回,不會丟擲異常。
3 join函式分析
Thread#join:publicfinalvoid join() throws InterruptedException { join(0); } publicfinalvoid join(long millis) throws InterruptedException { synchronized(lock) { long base = System.currentTimeMillis(); long now =0; if (millis <0) { thrownew IllegalArgumentException("timeout value is negative"); } if (millis ==0) { while (isAlive()) { lock.wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <=0) { break; } lock.wait(delay); now = System.currentTimeMillis() - base; } } } }說明,join()方法也可以理解為執行緒之間協作的一種方式,當兩個執行緒需要順序執行時,呼叫第一個執行緒的join()方法能使該執行緒阻塞,其依然通過wait()方法來實現的。
4 sleep與wait函式分析
Thread#sleep:public static void sleep(long millis) throws InterruptedException { Thread.sleep(millis, 0); }Thread#wait:
public final void wait(long millis) throws InterruptedException { wait(millis, 0); }說明,sleep()與wait()的相同之處在於它們都是通過等待阻塞執行緒,不同之處在於sleep()等待的是時間,wait()等待的是物件的鎖,在這裡是看不出來的。
5 常用函式總結
run():包含執行緒執行時所執行的程式碼
start():用於啟動執行緒
sleep()、sleep(long millis):執行緒休眠,交出CPU,讓CPU去執行其他的任務,然後執行緒進入阻塞狀態,sleep方法不會釋放鎖
yield():使當前執行緒交出CPU,讓CPU去執行其他的任務,但不會是執行緒進入阻塞狀態,而是重置為就緒狀態,yield方法不會釋放鎖
join()、join(long millis)、join(long millis,int nanoseconds):等待執行緒終止,直白的說 就是發起該子執行緒的執行緒 只有等待該子執行緒執行結束才能繼續往下執行
wait():交出cpu,讓CPU去執行其他的任務,讓執行緒進入阻塞狀態,同時也會釋放鎖
interrupt():中斷執行緒,自stop函式過時之後,我們通過interrupt方法和isInterrupted()方法來停止正在執行的執行緒,注意只能中斷已經處於阻塞的執行緒
getId():獲取當前執行緒的ID
getName()、setName():獲取和設定執行緒的名字
getPriority()、setPriority():獲取和這是執行緒的優先順序 一般property用1-10的整數表示,預設優先順序是5,優先順序最高是10,優先順序高的執行緒被執行的機率高
setDaemon()、isDaemo():設定和判斷是否是守護執行緒
currentThread():靜態函式獲取當前執行緒
參考文獻相關推薦
android執行緒管理二(Thread)
前言 一 結構關係 publicclassThreadimplementsRunnable{ ...... } 很顯然Thread繼承了Runnable。 Runnable原始碼如下: pub
多執行緒之旅(Thread)
在上篇文章中我們已經知道了多執行緒是什麼了,那麼它到底可以幹嘛呢?這裡特別宣告一個前面的委託沒看的同學可以到上上上篇博文檢視,因為多執行緒要經常使用到委託。原始碼 一、非同步、同步 1.同步(在計算的理解總是要你措不及防,同步
多執行緒基礎二(執行緒的啟動、終止,執行緒面臨的三種問題)
一、執行緒的啟動、終止方式 啟動: start native(呼叫外部介面啟動) 終止: stop(類似kill,暴力終止) interrupt 中斷的方式 通過指令的方式 volatile boolean stop
執行緒親和性(Thread Affinity)
原文連結 譯者:裘卡 如果你正在開發低延遲的網路應用,那應該對執行緒親和性(Thread affinity)有所瞭解。執行緒親和效能夠強制使你的應用執行緒執行在特定的一個或多個cpu上。通過這種方式,可以消除作業系統進行排程過程導致執行緒遷移所造成的影響。幸運的是,剛好有一個這麼一個java
執行緒的禮讓(Thread.yield())方法
在多執行緒裡面有各種各樣的方法,其中有一個禮讓的方法很有意思,現實生活中所謂的禮讓,就是“委屈自己方便他人”!比如過馬路,汽車禮讓行人,當然這是在國外,國內過個斑馬線是要看司機的性格的!那麼線上程中是
Android執行緒操作類(暫停、重新開啟、停止)
場景: 在程式中如果需要在後臺長時間做一件事情,比如聯網獲取資料等操作,就要用到執行緒。 但為了提高使用者體驗,有以下幾點需要注意: 1、程式可見時執行緒開始執行; 2、程式不可見時執行緒暫停; 3、程式退出時停止執行緒; 以下根據我自己的程式提出一個公用的程式碼,大家可以
Linux下的多執行緒程式設計二(執行緒的同步與互斥)
一、什麼叫做執行緒的同步與互斥?為什麼需要同步與互斥? 1、同步與互斥 互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。 同步:是指在互斥的基礎上(大多數情況),通過其它機制
C#中的執行緒(二)執行緒同步基礎 (讀後感)
一、lock 確保只有一個執行緒訪問某個資源或某段程式碼。通俗的講就是多個執行緒操作相同的鎖物件,只能一個執行緒操作完畢,例外的執行緒才能繼續訪問鎖定資原始碼 如下程式碼: 1.修改鎖定物件 的屬性 RYAreaEmpPathWayVM areaEmpPathWayVM = instance.system
iOS開發-多執行緒程式設計技術(Thread、Cocoa operations、GCD)
簡介 在軟體開發中,多執行緒程式設計技術被廣泛應用,相信多執行緒任務對我們來說已經不再陌生了。有了多執行緒技術,我們可以同做多個事情,而不是一個一個任務地進行。比如:前端和後臺作互動、大任務(需要耗費一定的時間和資源)等等。也就是說,我們可以使用執行緒把佔據時間長的任務放到後臺中處理,而不影響到使用者的使用
4.2執行緒區域性變數(Thread-Local Variables)
你有時候想要通過每個執行緒的資料(如一個使用者的ID)連線一個執行緒。儘管你可以使用區域性變數完成這個任務,僅僅只有區域性變數存在時你才可以這樣做。你可以用一個例項的欄位去長久儲存這個資料,但是你需要去處理同步。幸好,Java提供了java.lang.ThreadL
std::thread執行緒詳解(1)
## 目錄 - [目錄](#目錄) - [簡介](#簡介) - [執行緒的使用](#執行緒的使用) - [執行緒的建立](#執行緒的建立) - [執行緒的方法和屬性](#執行緒的方法和屬性) - [std::jthread (C++20)](#stdjthread-c20) - [sto
多執行緒詳解(一)
[多執行緒詳解(一)](http://www.neilx.com) 一、概念準備 1、程序 (1)直譯:正在進行中的程式 (2)解釋:執行一個程式時,會在記憶體中為程式開闢空間,這個空間就是一個程序。 (3)注意:一個程序中不可能沒有執行緒,只有有了執行緒才能執行; 程序只
Linux程式設計 多程序,多執行緒求解PI(圓周率)
題目: 連結 多程序: #include <unistd.h> #include <stdio.h> #include <stdlib.h> #define n 100000000.0 int main() { i
執行緒安全問題(迸發)入門知識總結
關於Java解決執行緒衝突的方法簡單總結 1.在方法面前使用synchronized或者使用方法塊 2.使用各種鎖lock,Reentrantlock,讀寫鎖 3.使用volatile保證可見性 4.使用ThreadLock複製變數副本 5.java.util.concurrent的API及St
多執行緒學習總結(一)
一、程序和執行緒的定義 程序:程序是資源(CPU、記憶體等)分配的基本單位,它是程式執行時的一個例項。程式執行時系統就會建立一個程序,併為它分配資源,然後把該程序放入程序就緒佇列,程序排程器選中它的時候就會為它分配CPU時間,程式開始真正執行。 執行緒:執行緒是程式執行時的最小單位,它是程序
【小家Java】一次Java執行緒池誤用(newFixedThreadPool)引發的線上血案和總結
相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9
java執行緒學習總結(一)
(宣告:並非原創,只是一個簡單總結) 一、執行緒和程序的概念: 程序:程序是處於執行過程中的程式,並且具有一定的對功能,是系統進行資源分配和排程的一個獨立單位。
第12章——《執行緒控制》(1)
實驗環境介紹 gcc:4.8.5 glibc:glibc-2.17-222.el7.x86_64 os:Centos7.4 kernel:3.10.0-693.21.1.el7.x86_64 執行緒限制 使用sysconf函式可以檢視一
java:多執行緒的基礎(引入)
* 1.什麼是執行緒 * 執行緒是程式執行的一條路徑, 一個程序中可以包含多條執行緒 * 多執行緒併發執行可以提高程式的效率, 可以同時完成多項工作* 2.多執行緒的應用場景 * 紅
java多執行緒快速入門(四)
通過匿名內部類的方法建立多執行緒 package com.cppdy; //通過匿名內部類的方法建立多執行緒 public class ThreadDemo2 { public static void main(String[] args) { new Thread(ne