轉(zhuǎn)載標(biāo)明出處:http://blog.csdn.net/lmj623565791/article/details/26938985
繼續(xù)并發(fā),貌似并發(fā)的文章很少有人看啊~哈~
今天準(zhǔn)備詳細(xì)介紹java并發(fā)包下的Executor,以及Java提供了很多靈活的且極其方便的線程池的創(chuàng)建。
嗯,那就慢慢說,大家肯定都學(xué)過Socket,JavaSe的時候?qū)懥奶斐绦颍螒虻姆?wù)器,以及Android程序自己需要提供服務(wù)器的,都會拿Socket來自己寫個:
最初我們的服務(wù)器可能寫成這樣:
1、單線程服務(wù)器
- package com.zhy.concurrency.executors;
-
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
-
- /**
- * 單線程Web服務(wù)器
- *
- * @author zhy
- *
- */
- public class SingleThreadWebServer
- {
-
- public static void main(String[] args) throws IOException
- {
-
- ServerSocket server = new ServerSocket(7711);
- while (true)
- {
- Socket client = server.accept();
- handleReq(client);
- }
-
- }
-
- /**
- * 處理請求
- * @param client
- */
- private static void handleReq(Socket client)
- {
- }
-
- }
這樣的服務(wù)器代碼很簡單,理論上也是正確的,但是在實現(xiàn)的環(huán)境中卻很糟糕,因為它每次只能處理一個請求,如果每個請求的耗時過長,后面的請求會長時間等待或者超時錯誤。
于是乎,出現(xiàn)了下面這種寫法:
2、每個請求分配一個線程的服務(wù)器
- package com.zhy.concurrency.executors;
-
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- /**
- * 為每個請求分配一個線程
- * @author zhy
- *
- */
- public class TaskPreThreadServer
- {
- public static void main(String[] args) throws IOException
- {
- ServerSocket server = new ServerSocket(8811);
- while (true)
- {
- final Socket client = server.accept();
- new Thread()
- {
- public void run()
- {
- handleReq(client);
- };
- }.start();
- }
- }
-
- protected static void handleReq(Socket client)
- {
-
- }
- }
為每一個請求開辟一個線程,首先我得承認(rèn)我也經(jīng)常用這樣的寫法~但是我們還是要吐槽下這樣寫法的不足:
a、線程的生命周期的開銷還是相當(dāng)高的,大量的線程的創(chuàng)建將消耗大量的計算機資源
b、可創(chuàng)建線程的數(shù)量存在一個限制值(這個值由平臺覺得,且受很多因素的制約),如果超過這個限制,可能會報OOM錯誤
c、在一定范圍內(nèi),增加線程可以提高系統(tǒng)吞吐量,但是超過了這個范圍,就物極必反了,只會降低程序的執(zhí)行速度。
所以我們要繼續(xù)改進(jìn)我們的服務(wù)器代碼,Executor提供了非常方便的方式:
3、基于Executor的服務(wù)器
- package com.zhy.concurrency.executors;
-
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.concurrent.Executor;
- import java.util.concurrent.Executors;
-
- /**
- * 基于Executor的服務(wù)器
- * @author zhy
- *
- */
- public class TaskExecutionServer
- {
- private static final int THREAD_COUNT = 100;
- private static final Executor exec = Executors
- .newFixedThreadPool(THREAD_COUNT);
-
- public static void main(String[] args) throws IOException
- {
- ServerSocket server = new ServerSocket(9911);
- while (true)
- {
- final Socket client = server.accept();
- Runnable task = new Runnable()
- {
- @Override
- public void run()
- {
- handleReq(client);
- }
- };
- exec.execute(task);
- }
-
- }
-
- protected static void handleReq(Socket client)
- {
-
- }
- }
創(chuàng)建一個固定長度的線程池,既解決了單線程的阻塞問題,也解決了無限創(chuàng)建線程帶來的內(nèi)存消耗過多等問題。
4、Executors的API介紹
Java類庫提供了許多靜態(tài)方法來創(chuàng)建一個線程池:
a、newFixedThreadPool 創(chuàng)建一個固定長度的線程池,當(dāng)?shù)竭_(dá)線程最大數(shù)量時,線程池的規(guī)模將不再變化。
b、newCachedThreadPool 創(chuàng)建一個可緩存的線程池,如果當(dāng)前線程池的規(guī)模超出了處理需求,將回收空的線程;當(dāng)需求增加時,會增加線程數(shù)量;線程池規(guī)模無限制。
c、newSingleThreadPoolExecutor 創(chuàng)建一個單線程的Executor,確保任務(wù)對了,串行執(zhí)行
d、newScheduledThreadPool 創(chuàng)建一個固定長度的線程池,而且以延遲或者定時的方式來執(zhí)行,類似Timer;后面后單獨使用Blog介紹它與Timer區(qū)別
小結(jié)一下:在線程池中執(zhí)行任務(wù)比為每個任務(wù)分配一個線程優(yōu)勢更多,通過重用現(xiàn)有的線程而不是創(chuàng)建新線程,可以在處理多個請求時分?jǐn)偩€程創(chuàng)建和銷毀產(chǎn)生的巨大的開銷。當(dāng)請求到達(dá)時,通常工作線程已經(jīng)存在,提高了響應(yīng)性;通過配置線程池的大小,可以創(chuàng)建足夠多的線程使CPU達(dá)到忙碌狀態(tài),還可以防止線程太多耗盡計算機的資源。
好了,結(jié)束~歡迎大家留言~
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。