最近在項(xiàng)目中接觸到了很多有關(guān)于多線程方面的東西,并且剛好前段時(shí)間看了Java并發(fā)編程實(shí)戰(zhàn)那本說, 打算首先介紹一下,Java多線程相關(guān)的基礎(chǔ),例如Thread,Runnable。雖然這個(gè)極其的基礎(chǔ),但是我覺得任何東西都 應(yīng)該會(huì)分幾篇博客來總結(jié)相關(guān)的知識(shí)。當(dāng)然其中肯定會(huì)有一些錯(cuò)誤之處,歡迎留言指出。我會(huì)及時(shí)更正。 以上相關(guān)所有知識(shí)點(diǎn),有許多借鑒自其他的大神的博客,由于看了許多,沒辦法一一列舉,在此表示感謝。許多概念相關(guān)的知識(shí)來自于《Java并發(fā)編程實(shí)戰(zhàn)》那本書。 一、Thread 繼承Thread類,重寫run方法。 我覺得Thread應(yīng)該是被最經(jīng)常用到的。當(dāng)只需要一個(gè)簡單的線程,不需要管理線程時(shí)直接: new Thread(){ @Override public void run() { //請求網(wǎng)絡(luò)等 } }.start();123456123456 一個(gè)匿名內(nèi)部類就寫完了,相信很多人都寫過這樣的代碼。需要注意的是,如果在Activity中寫這樣的代碼很容易造成內(nèi)存泄露。 二、 Runnable 實(shí)現(xiàn)Runnable接口重寫run()方法 public class DisableRunnable implements Runnable{ @Override public void run() { //請求網(wǎng)絡(luò)等 } }12345671234567 Runnable 是執(zhí)行任務(wù)的單元,需要用Thread包裝一下才可以執(zhí)行。 每當(dāng)我們看到這樣的代碼時(shí): new Thread(){runnable}.start(); 當(dāng)你考慮用更靈活的策略來執(zhí)行任務(wù)時(shí),可以考慮利用線程池代替Thread。 三、 線程池: 下面主要說一下線程池相關(guān)的總結(jié), 最頂層接口 Executor public interface Executor { void execute(Runnable command); }1234512345 ExecutorService接口 繼承Executor 定義了一些有關(guān)于生命周期的方法。 public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }123456789101112131415161718192021222324252627282930123456789101112131415161718192021222324252627282930 ThreadPoolExecutor 間接實(shí)現(xiàn)了ExecutorService 是真正做事的線程池。最常見的幾種線程池都是它的實(shí)現(xiàn)。 ThreadPoolExecutor 常用的構(gòu)造方法: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler){}123456123456 相關(guān)參數(shù)解釋: 1.當(dāng)線程池小于corePoolSize時(shí),新提交任務(wù)將創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),即使此時(shí)線程池中存在空閑線程。 注意: 四、這里BlockingQueue SynchronousQueue LinkedBlockingQueue ArrayBlockingQueue PriorityBlockingQueue 優(yōu)先級(jí)隊(duì)列 Executors 線程池工具類,用于生產(chǎn)線程池。 五、幾類比較常見的線程池: public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }1234512345 解釋:構(gòu)建一個(gè)固定數(shù)目的線程池。corePoolSize 與 maximumPoolSize 數(shù)值相等。當(dāng)線程池中沒有空閑線程時(shí),利用 LinkedBlockingQueue public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }123456123456 解釋:構(gòu)建一個(gè)單線程(只有一個(gè)線程,單不一定是同一個(gè)線程)的線程池。corePoolSize 與 maximumPoolSize 均為1 .利用無界的LinkedBlockingQueue 作為保存任務(wù)的隊(duì)列,這樣就保證無論提交多少個(gè)人物,線程池只能有一個(gè)線程在運(yùn)行,其余的任務(wù)均保存在 LinkedBlockingQueue 隊(duì)列中。 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }1234512345 解釋:構(gòu)建一個(gè)具有緩存功能的線程池,corePoolSize = 0, maximumPoolSize = Integer.MAX_VALUE 。隊(duì)列用的是SynchronousQueue。每加入一個(gè)任務(wù),線程池便會(huì)構(gòu)建一個(gè)線程將它取出執(zhí)行(如果有空閑的線程,會(huì)利用空閑的線程,而不會(huì)創(chuàng)建新的線程),這樣,加入多少個(gè)任務(wù)便會(huì)創(chuàng)建相同個(gè)數(shù)的線程。所以這個(gè)線程池的 maximumPoolSize 為Integer.MAX_VALUE。這就保證了線程池的最大線程數(shù)是無界的,理論上線程池可以有任意個(gè)線程。當(dāng)線程執(zhí)行完任務(wù)后,超過60秒的空閑時(shí)間即被回收銷毀。 六、飽和策略: RejectedExecutionHandler 參數(shù)用來表示飽和策略。即表示當(dāng)有界隊(duì)列已滿,并且當(dāng)前線程池中的線程數(shù)已達(dá)到 maximumPoolSize ,這時(shí)再提交任務(wù),會(huì)交給RejectedExecutionHandler 來處理。 注意:這里一定是有界隊(duì)列,因?yàn)闊o界隊(duì)列我們認(rèn)為是永遠(yuǎn)也無法填滿的(SynchronousQueue直接由生產(chǎn)者提交給工作線程),那么也就永不到飽和策略了。 public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }1234512345 RejectedExecutionHandler 本身是一個(gè)接口。在Executors中提供了幾個(gè)實(shí)現(xiàn)類。 1)AbortPolicy:中止,executor拋出未檢查RejectedExecutionException,調(diào)用者捕獲這個(gè)異常,然后自己編寫能滿足自己需求的處理代碼。 2)DiscardRunsPolicy:遺棄最舊的,選擇丟棄的任務(wù),是本應(yīng)接下來就執(zhí)行的任務(wù)。 3)DiscardPolicy:遺棄會(huì)默認(rèn)放棄最新提交的任務(wù)(這個(gè)任務(wù)不能進(jìn)入隊(duì)列等待執(zhí)行時(shí)) 4)CallerRunsPolicy:調(diào)用者運(yùn)行,既不會(huì)丟棄哪個(gè)任務(wù),也不會(huì)拋出任何異常,把一些任務(wù)推回到調(diào)用者那里,以此減緩新任務(wù)流。它不會(huì)在池線程中執(zhí)行最新提交的任務(wù),但它會(huì)在一個(gè)調(diào)用了execute的線程中執(zhí)行。 七、線程工廠: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {} public interface ThreadFactory { Thread newThread(Runnable r); }1234567891011121312345678910111213 ThreadFactory 在 Executors 中也提供了幾個(gè)實(shí)現(xiàn)類,一般博主所接觸過的都是 DefaultThreadFactory 。當(dāng)然我們可以自己定制, 八、常見的線程池的使用: 自定義線程池: private final static ExecutorService executorService = new ThreadPoolExecutor( 5, 10, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { //DO nothing } });123456789101112123456789101112 這里我們用的是自定義的線程池。我們定義了一個(gè)核心線程池為5的線程池,線程池內(nèi)最大的線程池?cái)?shù)為10。 當(dāng)然由于我們這里定義的緩存隊(duì)列為LinkedBlockingQueue, 沒有制定隊(duì)列大小,那么其默認(rèn)無Integer.MAX_VALUE。 飽和策略也是自定的,這里當(dāng)達(dá)到執(zhí)行飽和策略時(shí),什么都不做,直接丟棄。 public void request() { executorService.execute(new Runnable() { @Override public void run() { try { //請求網(wǎng)絡(luò)等。 } catch (Exception e) { e.printStackTrace(); } } }); } 利用Executors 提供的線程池: public void request() { ExecutorService executor = Executors.newFixedThreadPool(5); executor.execute(new Runnable() { @Override public void run() { try { //請求網(wǎng)絡(luò)等。 } catch (Exception e) { e.printStackTrace(); } } }); }1234567891011121314151617181920212223242526272829303112345678910111213141516171819202122232425262728293031 OK, 線程池相關(guān)就介紹到這里,下一篇會(huì)介紹Future,FutureTask, Callable 等等相關(guān)知識(shí)。 |
|