前言
最近在一直準備總結一下Android上的執行緒管理,今天先來總結一下Thread使用。
執行緒管理相關文章地址:
- Android執行緒管理之Thread使用總結
- Android執行緒管理之ExecutorService執行緒池
- Android執行緒管理之ThreadPoolExecutor自定義執行緒池
- Android執行緒管理之AsyncTask非同步任務
- Android執行緒管理之ThreadLocal理解及應用場景
實現Thread兩種方式
1.)繼承Thread類
/** * 繼承Thread方式 */ private class SyncThread extends Thread { SyncThread(String name) { super(name); } @Override public void run() { //執行耗時操作 } }
示例:
SyncThread syncThread1 = new SyncThread("執行緒一"); SyncThread syncThread2 = new SyncThread("執行緒二"); SyncThread syncThread3 = new SyncThread("執行緒三"); syncThread1.start(); syncThread2.start(); syncThread3.start();
2.)實現Runnable介面
/** * 實現Runnable方式 */ private class SyncRunnable implements Runnable { @Override public void run() { //執行耗時操作 } }
示例:
SyncRunnable syncRunnable = new SyncRunnable(); Thread syncThread1 = new Thread(syncRunnable, "執行緒一"); Thread syncThread2 = new Thread(syncRunnable, "執行緒二"); Thread syncThread3 = new Thread(syncRunnable, "執行緒三"); syncThread1.start(); syncThread2.start(); syncThread3.start();
Thread主要函式
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()//靜態函式獲取當前執行緒
Thread執行緒主要狀態
(1) New 一旦被例項化之後就處於new狀態
(2) Runnable 呼叫了start函式之後就處於Runnable狀態
(3) Running 執行緒被cpu執行 呼叫run函式之後 就處於Running狀態
(4) Blocked 呼叫join()、sleep()、wait()使執行緒處於Blocked狀態
(5) Dead 執行緒的run()方法執行完畢或被中斷或被異常退出,執行緒將會到達Dead狀態
如何停止一個執行緒
通過上面的函式列表,我可以知道通過interrupt方法和isInterrupted()方法來停止正在執行的執行緒,首先必須先讓執行緒處於阻塞狀態
/** * 銷燬執行緒方法 */ private void destroyThread() { try { if (null != thread && Thread.State.RUNNABLE == thread .getState()) { try { Thread.sleep(500); thread .interrupt(); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } finally { thread = null; } }
Thread執行緒同步問題
執行緒的同步是為了防止多個執行緒訪問一個資料物件時,造成資料不一致的問題。
1.)舉例說明:比如多執行緒操作一個全域性變數
private int count = 100; private boolean isRunning = false; private void test1() { isRunning=true; SyncThread syncThread1 = new SyncThread("執行緒一"); SyncThread syncThread2 = new SyncThread("執行緒二"); SyncThread syncThread3 = new SyncThread("執行緒三"); syncThread1.start(); syncThread2.start(); syncThread3.start(); } /** * 繼承Thread方式 */ private class SyncThread extends Thread { SyncThread(String name) { super(name); } @Override public void run() { while (isRunning) { count(); } } }
未加同步的count函式
private void count() { if (count > 0) { Log.e(TAG, Thread.currentThread().getName() + "--->" + count--); } else { isRunning = false; } }
執行結果:仔細觀察會發現有資料錯亂的現象
新增同步的count函式
private void count() { synchronized (this) { if (count > 0) { Log.e(TAG, Thread.currentThread().getName() + "--->" + count--); } else { isRunning = false; } } }
執行結果
2.)執行緒同步的幾種方式
同樣還是以上面的為例
(1)同步函式
private synchronized void count() { if (count > 0) { Log.e(TAG, Thread.currentThread().getName() + "--->" + count--); } else { isRunning = false; } }
(2)同步程式碼塊
private void count() { synchronized (this) { if (count > 0) { Log.e(TAG, Thread.currentThread().getName() + "--->" + count--); } else { isRunning = false; } } }
(3)使用特殊域變數(volatile)實現執行緒同步
private volatile int count = 1000;
a.volatile關鍵字為域變數的訪問提供了一種免鎖機制,
b.使用volatile修飾域相當於告訴虛擬機器該域可能會被其他執行緒更新,
c.因此每次使用該域就要重新計算,而不是使用暫存器中的值
d.volatile不會提供任何原子操作,它也不能用來修飾final型別的變數
(4)使用重入鎖實現執行緒同步
ReentrantLock() : 建立一個ReentrantLock例項
lock() : 獲得鎖
private void count() { lock.lock(); if (count > 0) { Log.e(TAG, Thread.currentThread().getName() + "--->" + count--); } else { isRunning = false; } lock.unlock(); }