如果并發(fā)的線程數(shù)量很多,并且每個線程都是執(zhí)行一個時間很短的任務(wù)就結(jié)束了,這樣頻繁創(chuàng)建線程就會大大降低系統(tǒng)的效率,因為頻繁創(chuàng)建線程和銷毀線程需要時間。 o 那么有沒有一種辦法使得線程可以復(fù)用,就是執(zhí)行完一個任務(wù),并不被銷毀,而是可以繼續(xù)執(zhí)行其他的任務(wù)?
ThreadPoolExecutor構(gòu)造器中各個參數(shù)的含義:corePoolSize:核心池的大小這個參數(shù)跟后面講述的線程池的實現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后,默認情況下,線程池中并沒有任何線程,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù),除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個線程或者一個線程。默認情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0,當(dāng)有任務(wù)來之后,就會創(chuàng)建一個線程去執(zhí)行任務(wù),當(dāng)線程池中的線程數(shù)目達到corePoolSize后,就會把到達的任務(wù)放到緩存隊列當(dāng)中;maximumPoolSize:線程池最大線程數(shù),這個參數(shù)也是一個非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個線程;keepAliveTime:表示線程沒有任務(wù)執(zhí)行時最多保持多久時間會終止。默認情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時,keepAliveTime才會起作用,直到線程池中的線程數(shù)不大于corePoolSize,即當(dāng)線程池中的線程數(shù)大于corePoolSize時,如果一個線程空閑的時間達到keepAliveTime,則會終止。直到線程池中的線程數(shù)不超過corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時,keepAliveTime參數(shù)也會起作用,直到線程池中的線程數(shù)為0;unit:參數(shù)keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態(tài)屬性:TimeUnit.DAYS; //天TimeUnit.HOURS; //小時TimeUnit.MINUTES; //分鐘TimeUnit.SECONDS; //秒TimeUnit.MILLISECONDS; //毫秒TimeUnit.MICROSECONDS; //微妙TimeUnit.NANOSECONDS; //納秒workQueue:一個阻塞隊列,用來存儲等待執(zhí)行的任務(wù),這個參數(shù)的選擇也很重要,會對線程池的運行過程產(chǎn)生重大影響,一般來說,這里的阻塞隊列有以下幾種選擇:ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue;線程池的排隊策略與BlockingQueue有關(guān)。threadFactory:線程工廠,主要用來創(chuàng)建線程;handler:表示當(dāng)拒絕處理任務(wù)時的策略,有以下四種取值:ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。 ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。 ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù) ThreadPoolExecutor類中有幾個非常重要的方法:execute()submit()shutdown()shutdownNow()getQueue() 、getPoolSize() 、getActiveCount()、getCompletedTaskCount()等獲取與線程池相關(guān)屬性的方法execute()方法實際上是Executor中聲明的方法,在ThreadPoolExecutor進行了具體的實現(xiàn),這個方法是ThreadPoolExecutor的核心方法,通過這個方法可以向線程池提交一個任務(wù),交由線程池去執(zhí)行?! ubmit()方法是在ExecutorService中聲明的方法,在AbstractExecutorService就已經(jīng)有了具體的實現(xiàn),在ThreadPoolExecutor中并沒有對其進行重寫,這個方法也是用來向線程池提交任務(wù)的,但是它和execute()方法不同,它能夠返回任務(wù)執(zhí)行的結(jié)果,去看submit()方法的實現(xiàn),會發(fā)現(xiàn)它實際上還是調(diào)用的execute()方法,只不過它利用了Future來獲取任務(wù)執(zhí)行結(jié)果(Future相關(guān)內(nèi)容將在下一篇講述)?! hutdown()和shutdownNow()是用來關(guān)閉線程池的。.深入剖析線程池實現(xiàn)原理1.線程池狀態(tài)volatile int runState;static final int RUNNING = 0;static final int SHUTDOWN = 1;static final int STOP = 2;static final int TERMINATED = 3;runState表示當(dāng)前線程池的狀態(tài),它是一個volatile變量用來保證線程之間的可見性; 下面的幾個static final變量表示runState可能的幾個取值?! ‘?dāng)創(chuàng)建線程池后,初始時,線程池處于RUNNING狀態(tài); 如果調(diào)用了shutdown()方法,則線程池處于SHUTDOWN狀態(tài),此時線程池不能夠接受新的任務(wù),它會等待所有任務(wù)執(zhí)行完畢; 如果調(diào)用了shutdownNow()方法,則線程池處于STOP狀態(tài),此時線程池不能接受新的任務(wù),并且會去嘗試終止正在執(zhí)行的任務(wù);當(dāng)線程池處于SHUTDOWN或STOP狀態(tài),并且所有工作線程已經(jīng)銷毀,任務(wù)緩存隊列已經(jīng)清空或執(zhí)行結(jié)束后,線程池被設(shè)置為TERMINATED狀態(tài)。private final BlockingQueueworkQueue; //任務(wù)緩存隊列,用來存放等待執(zhí)行的任務(wù)private final ReentrantLock mainLock = new ReentrantLock(); //線程池的主要狀態(tài)鎖,對線程池狀態(tài)(比如線程池大小 //、runState等)的改變都要使用這個鎖private final HashSetworkers = new HashSet(); //用來存放工作集 private volatile long keepAliveTime; //線程存活時間 private volatile boolean allowCoreThreadTimeOut; //是否允許為核心線程設(shè)置存活時間private volatile int corePoolSize; //核心池的大?。淳€程池中的線程數(shù)目大于這個參數(shù)時,提交的任務(wù)會被放進任務(wù)緩存隊列)private volatile int maximumPoolSize; //線程池最大能容忍的線程數(shù) private volatile int poolSize; //線程池中當(dāng)前的線程數(shù) private volatile RejectedExecutionHandler handler; //任務(wù)拒絕策略 private volatile ThreadFactory threadFactory; //線程工廠,用來創(chuàng)建線程 private int largestPoolSize; //用來記錄線程池中曾經(jīng)出現(xiàn)過的最大線程數(shù)private long completedTaskCount; //用來記錄已經(jīng)執(zhí)行完畢的任務(wù)個數(shù)corePoolSize在很多地方被翻譯成核心池大小,其實我的理解這個就是線程池的大小。
舉個簡單的例子: 假如有一個工廠,工廠里面有10個工人,每個工人同時只能做一件任務(wù)。 因此只要當(dāng)10個工人中有工人是空閑的,來了任務(wù)就分配給空閑的工人做; 當(dāng)10個工人都有任務(wù)在做時,如果還來了任務(wù),就把任務(wù)進行排隊等待; 如果說新任務(wù)數(shù)目增長的速度遠遠大于工人做任務(wù)的速度,那么此時工廠主管可能會想補救措施,比如重新招4個臨時工人進來; 然后就將任務(wù)也分配給這4個臨時工人做; 如果說著14個工人做任務(wù)的速度還是不夠,此時工廠主管可能就要考慮不再接收新的任務(wù)或者拋棄前面的一些任務(wù)了?! ‘?dāng)這14個工人當(dāng)中有人空閑時,而新任務(wù)增長的速度又比較緩慢,工廠主管可能就考慮辭掉4個臨時工了,只保持原來的10個工人,畢竟請額外的工人是要花錢的。? 這個例子中的corePoolSize就是10,而maximumPoolSize就是14(10+4)。也就是說corePoolSize就是線程池大小,maximumPoolSize就是線程池的一種補救措施,即任務(wù)量突然過大時的一種補救措施。1)首先,要清楚corePoolSize和maximumPoolSize的含義; 2)其次,要知道Worker是用來起到什么作用的; 3)要知道任務(wù)提交給線程池之后的處理策略,這里總結(jié)一下主要有4點:如果當(dāng)前線程池中的線程數(shù)目小于corePoolSize,則每來一個任務(wù),就會創(chuàng)建一個線程去執(zhí)行這個任務(wù);如果當(dāng)前線程池中的線程數(shù)目>=corePoolSize,則每來一個任務(wù),會嘗試將其添加到任務(wù)緩存隊列當(dāng)中,若添加成功,則該任務(wù)會等待空閑線程將其取出去執(zhí)行;若添加失?。ㄒ话銇碚f是任務(wù)緩存隊列已滿),則會嘗試創(chuàng)建新的線程去執(zhí)行這個任務(wù);如果當(dāng)前線程池中的線程數(shù)目達到maximumPoolSize,則會采取任務(wù)拒絕策略進行處理;如果線程池中的線程數(shù)量大于 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止,直至線程池中的線程數(shù)目不大于corePoolSize;如果允許為核心池中的線程設(shè)置存活時間,那么核心池中的線程空閑時間超過keepAliveTime,線程也會被終止。3.線程池中的線程初始化 默認情況下,創(chuàng)建線程池之后,線程池中是沒有線程的,需要提交任務(wù)之后才會創(chuàng)建線程?! ≡趯嶋H中如果需要線程池創(chuàng)建之后立即創(chuàng)建線程,可以通過以下兩個方法辦到:prestartCoreThread():初始化一個核心線程;prestartAllCoreThreads():初始化所有核心線程4.任務(wù)緩存隊列及排隊策略 在前面我們多次提到了任務(wù)緩存隊列,即workQueue,它用來存放等待執(zhí)行的任務(wù)?! orkQueue的類型為BlockingQueue,通??梢匀∠旅嫒N類型:
1)ArrayBlockingQueue:基于數(shù)組的先進先出隊列,此隊列創(chuàng)建時必須指定大小;
2)LinkedBlockingQueue:基于鏈表的先進先出隊列,如果創(chuàng)建時沒有指定此隊列大小,則默認為Integer.MAX_VALUE;
3)synchronousQueue:這個隊列比較特殊,它不會保存提交的任務(wù),而是將直接新建一個線程來執(zhí)行新來的任務(wù)。
5.任務(wù)拒絕策略
當(dāng)線程池的任務(wù)緩存隊列已滿并且線程池中的線程數(shù)目達到maximumPoolSize,如果還有任務(wù)到來就會采取任務(wù)拒絕策略,通常有以下四種策略:
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
線程池的關(guān)閉
ThreadPoolExecutor提供了兩個方法,用于線程池的關(guān)閉,分別是shutdown()和shutdownNow(),其中:
shutdown():不會立即終止線程池,而是要等所有任務(wù)緩存隊列中的任務(wù)都執(zhí)行完后才終止,但再也不會接受新的任務(wù)
shutdownNow():立即終止線程池,并嘗試打斷正在執(zhí)行的任務(wù),并且清空任務(wù)緩存隊列,返回尚未執(zhí)行的任務(wù)
7.線程池容量的動態(tài)調(diào)整
ThreadPoolExecutor提供了動態(tài)調(diào)整線程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),
setCorePoolSize:設(shè)置核心池大小
setMaximumPoolSize:設(shè)置線程池最大能創(chuàng)建的線程數(shù)目大小
當(dāng)上述參數(shù)從小變大時,ThreadPoolExecutor進行線程賦值,還可能立即創(chuàng)建新的線程來執(zhí)行任務(wù)。
1) 請求處理
2) Dispatcher任務(wù)調(diào)度:
主要的變量
構(gòu)造函數(shù)
異步請求
AsyncCall
1) Interceptor攔截器
2) 緩存策略
3) 失敗重連
http://blog.csdn.net/qq_33463102/article/details/60869879(攔截器)
一、什么是攔截器?
攔截器是一種能夠監(jiān)控,重寫,重試調(diào)用的強大機制。我們可以使用攔截器添加我們的頭信息,網(wǎng)絡(luò)請求,網(wǎng)絡(luò)緩存等。
? 攔截器的分類:(兩大類):
1) 應(yīng)用攔截器(Application Interceptors)
2) 網(wǎng)絡(luò)攔截器(NetWork Interceptors)
應(yīng)用攔截器:應(yīng)用攔截器一般使用最多的是打印日志,查看請求信息及返回信息
網(wǎng)絡(luò)攔截器:可以添加、刪除或替換請求頭信息,還可以改變的請求攜帶的實體
自定義網(wǎng)絡(luò)攔截器:
Interceptor?interceptor?=?new?Interceptor()?{??
????????@Override??
????????public?Response?intercept(Chain?chain)?throws?IOException?{??
????????????Request?request?=?chain.request();??
????????????Response?response?=?chain.proceed(request);??
????????????String?cacheControl?=?request.cacheControl().toString();??
????????????if?(TextUtils.isEmpty(cacheControl))?{??
????????????????cacheControl?=?"public,?max-age=60";??
????????????}??
????????????return?response.newBuilder()??
????????????????????.header("Cache-Control",?cacheControl)??
????????????????????.removeHeader("Pragma")??
????????????????????.build();??
????????}??
????};??
設(shè)置client:
//設(shè)置緩存路徑??
????????File?httpCacheDirectory?=?new?File(mContext.getCacheDir(),?"responses");??
????????//設(shè)置緩存?10M??
????????Cache?cache?=?new?Cache(httpCacheDirectory,?10?*?1024?*?1024);??
????????//創(chuàng)建OkHttpClient,并添加攔截器和緩存代碼??
????????OkHttpClient?client?=?new?OkHttpClient.Builder()??
????????????????.addNetworkInterceptor(interceptor)??
????????????????.cache(cache)??
????????.build();??
FORCE_NETWORK常量是用來使用網(wǎng)絡(luò)請求。FORCE_CACHE只取本地的緩存。不同于攔截器設(shè)置緩存,CacheControl是針對Request的,所以它可以針對每個請求設(shè)置不同的緩存策略。
//緩存文件夾??
File?cacheFile?=?new?File(getExternalCacheDir().toString(),"cache");??
//緩存大小為10M??
int?cacheSize?=?10?*?1024?*?1024;??
//創(chuàng)建緩存對象??
final?Cache?cache?=?new?Cache(cacheFile,cacheSize);??
?OkHttpClient?client?=?new?OkHttpClient.Builder()??
????????????????????????.cache(cache)??
????????????????????????.build();??
????????????????//設(shè)置緩存時間為60秒??
????????????????CacheControl?cacheControl?=?new?CacheControl.Builder()??
????????????????????????.maxAge(60,?TimeUnit.SECONDS)??
????????????????????????.build();??
????????????????Request?request?=?new?Request.Builder()??
????????????????????????.url(URL)??
????????????????????????.cacheControl(cacheControl)??
????????????????????????.build();??
強制使用緩存:CacheControl.FORCE_CACHE這個常量
public?static?final?CacheControl?FORCE_CACHE?=?new?Builder()??
??????.onlyIfCached()??
??????.maxStale(Integer.MAX_VALUE,?TimeUnit.SECONDS)??
??????.build();??
Request?request?=?new?Request.Builder()??
????????????.url(URL)??
????????????.cacheControl(Cache.FORCE_CACHE)??
????????????.build();??
不使用緩存:CacheControl.FORCE_NETWORK這個常量(第一種方案)
public?static?final?CacheControl?FORCE_NETWORK?=?new?Builder().noCache().build();??
Request?request?=?new?Request.Builder()??
????????????.url(URL)??
????????????.cacheControl(Cache.FORCE_NETWORK)??
????????????.build();??
不使用緩存:將maxAge設(shè)置為0,也會直接訪問網(wǎng)絡(luò)(第二種方案)
Request?request?=?new?Request.Builder()??
????????????.url(URL)??
????????????.cacheControl(new?CacheControl.Builder()??
????????????.maxAge(0,?TimeUnit.SECONDS))??
????????????.build();??
Okhttp3設(shè)置緩存:
OkHttpClient?okHttpClient?=?new?OkHttpClient();??
OkHttpClient?newClient?=?okHttpClient.newBuilder()??
???????????????.cache(new?Cache(mContext.getCacheDir(),?10*1240*1024))??
???????????????.connectTimeout(20,?TimeUnit.SECONDS)??
???????????????.readTimeout(20,?TimeUnit.SECONDS)??
???????????????.build();??