1. 程式人生 > >android執行緒管理二(Thread)

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
(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } public Thread(ThreadGroup group, Runnable target) { init(group, target, "Thread-" + nextThreadNum(), 0); } ......
  說明,這只是部分構造方法,從這些構造方法中可以看出都是呼叫了函式init。 Thread#init
/**     * 很明顯這個方法是用來初始化執行緒的     * @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++;
        }
}
註釋已經說的很清楚了:
/**
* 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.
*/
大致意思就是:把thread group 中的即將啟動的執行緒數加一,這樣可以在該執行緒沒有啟動的情況,避免被銷燬。

int

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);
        }
}
說明,這裡有兩點需要注意下: 類載入器即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函式完成執行緒的建立。

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