1.多線程套接字編程中的不足
記得之前做過學校的一個實驗,是關於多線程套接字編程地,在那次實驗中,我們採用瞭如下的代碼:
ServerSocket server = new ServerSocket(80);
while(true){
//新建線程
new Thread(xxx).start;
}
在上方代碼,我們爲了提升服務器的效率,我們使用了多線程編程,但是同時,這個代碼,他也是會無限制創建線程地,他的不足主要有:
1.線程每次創建和銷燬的代價非常高;2.對內存的消耗很大,可運行的線程數量很可能多於處理器數量;3.穩定性,如果線程超過了當前虛擬機或者操作系統的限制,那很可能拋出異常。
針對這種代碼,我們給出了更好的解決方案,就是使用線程池。
2.1關於Executor框架和線程池
Excetor是一個接口,它裏面就是一個execute方法,參數是Runnable類型,作用就是執行這個實現了Runable接口的類的線程。很簡單,但是爲靈活且強大的線程池(異步執行框架)提供了基礎。
關於線程池的使用:
類A {
private static final Exceutor exex = Executors.newFixedThreadPool(100);
public static void main(String[] args)throws IOException{
ServerSocket socket = new ServerSocket(80);
Runnable task = new B//某個實現了Runnable的類
exec.execute(task);
}
}
關於線程池的優勢:1.可以寵用現有線程,而不用創建新線程,節省開銷;2.可以限定線程池大小,創建足夠多的線程讓系統保持忙碌,卻不會耗盡資源使任務失敗。
類庫提供了一些Executors靜態工廠方法來創建一個線程池:
1.newFixedThreadPool。 創建一個固定長度的線程池
2.newCachedThreadPool。 創建一個可緩存的線程池,如果線程池的當前規模超過了處理需求時,那麼將回收空閒的線程,而當需求增加時則可以添加新的線程,線程池的規模不存在任何限制。
3.newSingleThreadExecutor。這是一個單線程的線程池,他創建單個工作者線程來執行任務,如果這個線程異常結束,會創建另一個線程來代替。
4.newScheduledThreadPool。創建了一個固定長度的現車公尺,而且一延時或定時的方式來執行任務,類似Timer定時器。
newFixedThreadPool和newCachedThreadPool這兩個工廠方法返回通用的ThreadPoolExecutor實例,可以直接用來構造專門用途的exxecutor
2.2線程池的生命週期
ExecutorService 拓展了Executor接口,新增了關於結束線程池生命的方法,就是說,我們可以用ExecutorService接口,就可以承接真是的線程池實例類了。
主要方法有shutdown()//正常、安全、緩慢關閉; 還有shutdownnow//強行快速關閉線程池
2.3線程池和攜帶結果的任務,Callable和Future
Runnable是一種有侷限的抽象,run,它並不能返回一個值。所以我們有了Callable接口,他認爲主入口點(call方法)將返回一個值,並可能拋出一個異常。
Future表示一個任務的生命週期,並提供方法來判斷是否完成或者取消,獲取任務結果,他隱含了一個含義,任務的生命週期只能前進,不能後退。他也是一個接口。
get方法取決於任務狀態,如果任務還沒完成就會阻塞。
關於Future和Callable的使用例子,使用Future等待圖像下載:
class FutureRenderer {
private final ExecutorService executor = .;
void renderPage(CharSequence source) {
final List<ImageInfo> imageInfos = scanForImageInfo(source);
Callable<List<ImageData>> task = new Callable<List<ImageData>> () {
public List<ImageData> call() {
List<ImageData> result = new ArrayList<ImageData>();
for(ImageInfo imageInfo : imageInfos) {
result.add(imageInfo.downloadImage());
}
return result;
}
};
Future<List<ImageData>> future = executor.submit(task);
renderText(source);
try{
List<ImageData> imageData = future.get();
for(ImageData data : imageData) {
rederImage(data);
}
} catch (InterruptedException e) {
//重新設置線程的中斷狀態
Thread.currentThread().interrupt();
//由於不需要結束,因此取消任務
future.cancel(true);
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
}
}
}
我們還可以通過Future的get方法來爲任務設置時間限制:
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一樣,多了設置超時時間。參數timeout指定超時時間,uint指定時間的單位,在枚舉類TimeUnit中有相關的定義。如果計算超時,將拋出TimeoutException