我自己理解看來。線程池顧名思義就是一個容器的意思,需要注意的是,每一個線程都是需要CPU分配資源去執行的。如果由於總是new Thread()開啟一個線程,那麼就會大量的消耗CPU的資源,導致Android運行變慢,甚至OOM(out of memory),因而Java就出現了一個ThreadPoolExecutor來管理這些線程。控制最多的線程數maximumPoolSize,核心線程數corePoolSize,來管理我們需要開啟的線程數。這樣減少了建立和銷毀線程的次數,每個背景工作執行緒都可以被重複利用,可執行多個任務。所以,我們就可以根據手機的CPU核心數來控制App可以開的最大線程數,保證程式的合理運行。
在Android中當同時並發多個網路線程時,引入線程池技術會極大地提高APP的效能。例如:多線程下載,點一個下載一個(假設允許最多同時下載五個),當點到第六個的時候開始等待,這就涉及到線程的管理。
Android引入線程池好處是:提升了效能(建立和消耗對象費時費CPU資源);防止記憶體過度消耗(控制活動線程的數量,防止並發線程過多)。 1.ThreadPoolExecutor 1.ThreadPoolExecutor參數
jdk自身帶有線程池的實作類別ThreadPoolExecutor,使用ThreadPoolExecutor,瞭解其每個參數的意義是必不可少的。
ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler)
corePoolSize: 核心線程數,能夠同時執行的任務數量;
maximumPoolSize:除去緩衝隊列中等待的任務,最大能容納的任務數(其實是包括了核心線程池數量);
keepAliveTime:超出workQueue的等待任務的存活時間,就是指maximumPoolSize裡面的等待任務的存活時間;
unit:時間單位;
workQueue:阻塞等待線程的隊列,一般使用new LinkedBlockingQueue()這個,如果不指定容量,會一直往裡邊添加,沒有限制,workQueue永遠不會滿;
threadFactory:建立線程的工廠,使用系統預設的類;
handler:當任務數超過maximumPoolSize時,對任務的處理策略,預設策略是拒絕添加; 2.阻塞隊列
隊列用於排隊,避免一瞬間出現大量請求的問題。
阻塞隊列分為 有限隊列(SynchronousQueue、ArrayBlockingQueue)和 無限隊列(LinkedBloackingQueue)。 3.執行流程
當線程數小於corePoolSize時,每添加一個任務,則立即開啟線程執行;當corePoolSize滿的時候,後面添加的任務將放入緩衝隊列workQueue等待;當workQueue也滿的時候,看是否超過maximumPoolSize線程數,如果超過,預設拒絕執行。
下面我們看個例子:假如corePoolSize=2,maximumPoolSize=3,workQueue容量為8;最開始,執行的任務A,B,此時corePoolSize已用完,再次執行任務C,則C將被放入緩衝隊列workQueue中等待著,如果後來又添加了7個任務,此時workQueue已滿,則後面再來的任務將會和maximumPoolSize比較,由於maximumPoolSize為3,所以只能容納1個了,因為有2個在corePoolSize中運行了,所以後面來的任務預設都會被拒絕。 4.終止一個線程
我們編寫終止一個線程的 junit 測試方法:
private class MyRunnable implements Runnable { public volatile boolean flag = true; @Override public void run() { while (flag && !Thread.interrupted()) { try { System.out.println("running"); Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); return; //2.中斷線程時, 注意此處必須做處理 } } }}@Testpublic void RunnableTest() throws InterruptedException { MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); Thread.sleep(2000); runnable.flag = true; thread.interrupt(); //1.中斷線程}
2.封裝線程池管理者
下面我們基於ThreadPoolExecutor對線程池進行封裝:
/** * 線程池管理 管理整個項目中所有的線程,所以不能有多個執行個體對象 */public class ThreadPoolManager { /** * 單例設計模式(餓漢式) * 單例首先私人化構造方法,然後餓漢式一開始就開始建立,並提供get方法 */ private static ThreadPoolManager mInstance = new ThreadPoolManager(); public static ThreadPoolManager getInstance() { return mInstance; } private int corePoolSize;//核心線程池的數量,同時能夠執行的線程數量 private int maximumPoolSize;//最大線程池數量,表示當緩衝隊列滿的時候能繼續容納的等待任務的數量 private long keepAliveTime = 1;//存活時間 private TimeUnit unit = TimeUnit.HOURS; private ThreadPoolExecutor executor; private ThreadPoolManager() { /** * 給corePoolSize賦值:當前裝置可用處理器核心數*2 + 1,能夠讓cpu的效率得到最大程度執行(有研究論證的) */ corePoolSize = Runtime.getRuntime().availableProcessors()*2+1; maximumPoolSize = corePoolSize; //雖然maximumPoolSize用不到,但是需要賦值,否則報錯 executor = new ThreadPoolExecutor( corePoolSize, //當某個核心任務執行完畢,會依次從緩衝隊列中取出等待任務 maximumPoolSize, //5,先corePoolSize,然後new LinkedBlockingQueue<Runnable>(),然後maximumPoolSize,但是它的數量是包含了corePoolSize的 keepAliveTime, //表示的是maximumPoolSize當中等待任務的存活時間 unit, new LinkedBlockingQueue<Runnable>(), //緩衝隊列,用於存放等待任務,Linked的先進先出 Executors.defaultThreadFactory(), //建立線程的工廠 new ThreadPoolExecutor.AbortPolicy() //用來對超出maximumPoolSize的任務的處理策略 ); } /** * 執行任務 */ public void execute(Runnable runnable){ if(runnable==null)return; executor.execute(runnable); } /** * 從線程池中移除任務 */ public void remove(Runnable runnable){ if(runnable==null)return; executor.remove(runnable); }}
其中,擷取當前可用的處理器核心數我們用Runtime.getRuntime().availableProcessors(),我們來看它的注釋:
下面我們來看一下Runnable與線程的區別:
Runnable只是一個介面,它的源碼如下,而線程是真正開啟系統資源去執行任務,他們兩個,線程是真正消耗系統資源的
/** * Represents a command that can be executed. Often used to run code in a * different {@link Thread}. */public interface Runnable { /** * Starts executing the active part of the class' code. This method is * called when a thread is started that has been created with a class which * implements {@code Runnable}. */ public void run();}
到這裡已經基本上介紹完了線程池,下面我們通過實際編碼看一下如何使用線程池。 3.示範線程池的使用方法
下面是一個線程池的例子(示範多線程執行任務),以加深對原理的理解
1.引入我們封裝好的ThreadPoolManager.java
2.示範功能
/** * 示範線程池 */public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 建立九個任務 */ for (int i = 0; i < 9; i++) { ThreadPoolManager.getInstance().execute(new DownloadTask(i)); } } /** * 模仿下載任務,實現Runnable */ class DownloadTask implements Runnable{ private int num; public DownloadTask(int num) { super(); this.num = num; Log.d("JAVA", "task - "+num + " 等待中..."); } @Override public void run() { Log.d("JAVA", "task - "+num + " 開始執行了...開始執行了..."); SystemClock.sleep(5000); //類比延時執行的時間 Log.e("JAVA", "task - "+num + " 結束了..."); } }}
列印結果如下:
轉載:http://blog.csdn.net/smartbetter/article/details/52056272