轉載請聲明出處謝謝!http://www.cnblogs.com/linguanh/
這里主要使用Executors中的4種靜態創建線程池實例方法中的 newFixedThreadPool()來舉例講解。
簡單說下Executors類,提供的一系列創建線程池的方法:
他們都有兩個構造方法
1. --------newFixedThreadPool
(創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。)
public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
2. --------newSingleThreadExecutor
(創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。)
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory);
3. --------newCachedThreadPool
(創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程)
public static ExecutorService newCachedThreadPool();
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
4. --------newScheduledThreadPool
(創建一個定長線程池,支持定時及周期性任務執行。)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);
*******************************************
定長線程池-newFixedThreadPool 的第一個構造方法
public static ExecutorService newFixedThreadPool(int nThreads);傳入的參數nThreads是最大的同時進行、並發的線程數。如果我定義它是3,那么同時執行3個,超過的了就要排隊等待,流水線操作形式。
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
這個構造函數的第一個參數和上面的一個樣,第二個是線程工廠,它的作用:
文檔中是這樣說的:
這是什么意思呢? 其實就是說,在把線程加入線程池之前,都對它們共同進行一些操作,例如改變一些屬性。比如說setName(),thread-1和2、3、4 依次通過一個for 循環加入到線程池 中,他們的 Name 都會被改變。
線程池一般的使用方法:
通過 Executors.newFixedThreadPool(...).execute(Runnable()) 並發運行,例如下面的代碼片段
1 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); 2 for (int i = 0; i < 10; i++) { 3 final int index = i; 4 fixedThreadPool.execute(new Runnable() { 5 6 @Override 7 public void run() { 8 try { 9 Log.d("******", Thread.currentThread().getId() + " thread name: " + Thread.currentThread().getName()+"--"+index); 10 Thread.sleep(2000); 11 } catch (InterruptedException e) { 12 // TODO Auto-generated catch block 13 e.printStackTrace(); 14 } 15 } 16 }); 17 }
運行結果如下
因為線程池大小為3,最多3個同時運行,每個輸出index后sleep 2秒,所以每兩秒打印3個數字。
線程池和AsyncTask()結合使用:
AsyncTask() 知識惡補入口:http://www.2cto.com/kf/201203/122729.html
這里只說下 AsyncTask()的executeOnExecutor() 方法,它是3.0后新增的一個方法。executeOnExecutor(Executor exec, Object... params),
該方法接受2個參數:
第一個參數是Executor,即是我們的線程池實例,默認的可以傳入AsyncTask.THREAD_POOL_EXECUTOR,多線程並發,我們上面的是自定義的線程池,默認的最大並發5個,隊列最大128個,當然,我們可以new 一個ThreadPoolExecutor 實例,通過傳入參數改變這些限制;
第二個是任務參數。即是AsyncTask()中的第一個參數,我們可以在doInBackground()中獲取它,我下面的例子中,這個參數是字符串。
下面通過運行代碼看看它和 AsyncTask() 是怎樣聯系的:
1 package cn.mr.ams.threadpool; 2 3 import android.app.Activity; 4 import android.os.AsyncTask; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.Menu; 8 import android.view.MenuItem; 9 10 import java.util.concurrent.CyclicBarrier; 11 import java.util.concurrent.ExecutorService; 12 import java.util.concurrent.Executors; 13 import java.util.concurrent.ThreadFactory; 14 15 16 public class MyActivity extends Activity { 17 18 CyclicBarrier barrier = new CyclicBarrier(3); 19 public static int j = 0 ; 20 public final Object myTPLock = new Object();//對象鎖,主要用來實現同步,我這里並沒有使用 21 public static ExecutorService myTP = null;//和 AsyncTask() 連用 22 public static ExecutorService myTP_1 = Executors.newFixedThreadPool(3);//第一種構造函數 23 //private List<String> test = new ArrayList<String>(); 24 25 private String[] test = new String[]{"a--","b--","c--","d--","e--"}; 26 27 @Override 28 protected void onCreate(Bundle savedInstanceState) { 29 super.onCreate(savedInstanceState); 30 setContentView(R.layout.activity_my); 31 //采用 第二種 構造方法,改寫下 線程工廠 對象,使每次加入線程池中的線程都能被設置定義的屬性 32 myTP = Executors.newFixedThreadPool(3, new ThreadFactory() { 33 @Override 34 public Thread newThread(Runnable r) { 35 Thread t = new Thread(r); 36 //我把所加入到改線程池的線程全改名了 37 t.setName("LinGuanHong"); 38 // 設置線程的優先級別 39 t.setPriority(Thread.NORM_PRIORITY - 1); 40 return t; 41 } 42 }); 43 for(String item : test) { 44 //通過 for 循環,把 AsyncTask() 異步線程逐個 加入到線程池中 45 new myThread(barrier).executeOnExecutor(myTP,item); 46 //SystemClock.sleep(10);//能起到一定的延時,實現按順序進行 47 } 48 /*for (int i = 0; i < 10; i++) { 49 final int index = i; 50 myTP_1.execute(new Runnable() { 51 @Override 52 public void run() { 53 try { 54 Log.d("******", Thread.currentThread().getId() + " thread name: " + Thread.currentThread().getName()+"--"+index); 55 Thread.sleep(2000); 56 } catch (InterruptedException e) { 57 // TODO Auto-generated catch block 58 e.printStackTrace(); 59 } 60 } 61 }); 62 }*/ 63 64 } 65 66 67 public class myThread extends AsyncTask<Object, Void, String> { 68 private CyclicBarrier barrier = null; 69 public myThread(CyclicBarrier barrier){ 70 this.barrier = barrier; 71 } 72 73 @Override 74 protected String doInBackground(Object[] params) { 75 Object id = params[0]; 76 String idString = id.toString(); 77 //synchronized (myTPLock) { 78 Log.d("******", idString + " id: " + Thread.currentThread().getId() + " " + 79 "thread name: " + Thread.currentThread().getName()+" "+MyActivity.j); 80 //} 81 MyActivity.j++; 82 return null; 83 } 84 } 85 86 87 @Override 88 public boolean onCreateOptionsMenu(Menu menu) { 89 // Inflate the menu; this adds items to the action bar if it is present. 90 getMenuInflater().inflate(R.menu.my, menu); 91 return true; 92 } 93 94 @Override 95 public boolean onOptionsItemSelected(MenuItem item) { 96 // Handle action bar item clicks here. The action bar will 97 // automatically handle clicks on the Home/Up button, so long 98 // as you specify a parent activity in AndroidManifest.xml. 99 int id = item.getItemId(); 100 if (id == R.id.action_settings) { 101 return true; 102 } 103 return super.onOptionsItemSelected(item); 104 } 105 }
運行結果
在這里我們可以驗證,我們采用第二種構造方法,在線程工廠中改變 各線程的名字。
在我的代碼45行中,我通過for 循環有順序地傳入 a~e 字符串,但是這里的線程並沒有按照順序運行。即是並發了,因為AsyncTask本身是異步線程,我們再看上述代碼19行,我設置了個靜態的 int 標記,在 AsyncTask() 里面 78~81行沒打一次 log 就++,按照我們對異步、並發線程的理解,和可能就會出現,輸出的0~5是不按照順序的,但是上面是按照順序的,不僅僅是一次的截圖,我自己測試過很多次,0~5的輸出都是按順序的。
我自己的總結,可能不一定對,有錯請大家指出:
把AsyncTask()異步線程加入到線程池中運行,能夠很高效地提高執行任務的速度,如果不加其他操作限制,每個線程的執行可能是不按照順序的,但是,他們卻沒有出現搶占資源的狀況??