1. 程式人生 > >Java執行緒切換(一)

Java執行緒切換(一)

(本文由言念小文原創,轉載請註明出處)

一  前言
有Android開發經驗的同學都清楚,UI的更新必須在主執行緒中進行,且主執行緒不能被阻塞,否則系統ANR異常。我們往往做一些資料處理是耗時操作,必須要在子執行緒中進行,然後再將處理後的資料切換到主執行緒去更新UI,這便是執行緒切換。
執行緒切換的本質是“資料的切換”,即將資料從一個執行緒傳遞到另一個執行緒。

 

二  案例描述
老風格,先給出場景案例,然後通過執行緒切換實現該案例。
案例:線上程A中呼叫api傳送一段資料data,data最終通過執行緒切換由執行緒B執行資料處理動作。

 

三  執行緒切換基本原理
所謂執行緒切換,本質就是“資料線上程間切換”,即將一個執行緒A中的資料,傳遞到另一個執行緒B執行資料處理操作。基於以上認知,比較自然的實現邏就是:將執行緒A中的資料進行拷貝,執行緒B獲取到拷貝資料,然後進行處理,如下圖所示。

 

 

 

四 案例實現程式碼


首先建立一個DataHandler類,該類中定義了資料拷貝方法和資料處理執行緒。在DataHandler中定義了一個用於資料副本存放的成員變數mData;外部模組可通過sendData()將資料拷貝到DataHandler中;在DataHandler構造中初始化資料處理執行緒(執行緒B);該執行緒重寫的run()方法中用一個while迴圈不停查詢資料副本mData的值,當檢測到mData有資料時,則執行資料處理動作,資料處理完成後,將數副本mData清空。這樣便實現了將其他外部執行緒中的資料切換到執行緒B中處理。

public class DataHandler {
    
    // 資料副本
    private String mData;
    
    public DataHandler() {
        initSwithThread();
    }
    
    /**
     * 傳送資料,供外部呼叫
     * @param data
     */
    public void sendData(String data) {
        // 拷貝資料
        mData = data;
    }
    
    private void initSwithThread() {
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                while(true) {
                    if(null != mData && mData.length() > 0) {
                        System.out.println("process data, run in thread : " 
                                + Thread.currentThread().getName() + ", data = " + mData);
                        // 資料傳送後,清除資料副本mData
                        mData = null;
                    }
                    // 為了能夠清晰看清結果這裡讓thread休眠1s
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "ThreadB").start();
    }
}

測試類ThreadTest中建立執行緒A,然後在A中呼叫DataHandler例項的資料拷貝方法sendData()將資料切換到執行緒B中處理。

public class ThreadTest {
    
    public static DataHandler mHandler;
    
    public static void main(String[] args) {
        
        mHandler = new DataHandler();
        
        Thread threadA = new Thread(new Runnable() {
            
            @Override
            public void run() {
                // 執行緒A中傳送資料
                String data = "hello code 9527";
                System.out.println("send data, run in thread : " 
                        + Thread.currentThread().getName() + ", data = " + data);
                // 通過DataHandler將資料拷貝到執行緒B中處理
                mHandler.sendData(data);
                
            }
        }, "threadA");
        threadA.start();
          
    }

}

 

執行結果:
send data, run in thread : threadA, data = hello code 9527
process data, run in thread : ThreadB, data = hello code 9527


從結果可以看出資料“hello code 9527”線上程A中被DataHandler拷貝出來,副本存放到DataHandler中,然後通過執行緒B中進行處理。這樣就實現了資料線上程間的切換。實現切換的“靈魂操作”便是“資料拷貝”和“目標執行緒對拷貝副本的輪詢”。實現原理是不是很簡單?其實Android的Handler機制也是基於這種原理實現的,有興趣的同學可以深入分析一下Handler原始碼。

&n