Java中的阻塞和非阻塞IO包各自的優劣思考

來源:互聯網
上載者:User

 

Java中的阻塞和非阻塞IO包各自的優劣思考 

NIO 設計背後的基石:反應器模式,用於事件多路分離和指派的體繫結構模式。 

反應器(Reactor):用於事件多路分離和指派的體繫結構模式 

通常的,對一個檔案描述符指定的檔案或裝置, 有兩種工作方式: 阻塞 與非阻塞 。所謂阻塞方式的意思是指, 當試圖對該檔案描述符進行讀寫時, 如果當時沒有東西可讀,或者暫時不可寫, 程式就進入等待 狀態, 直到有東西可讀或者可寫為止。而對於非阻塞狀態, 如果沒有東西可讀, 或者不可寫, 讀寫函數馬上返回, 而不會等待 。 

一種常用做法是:每建立一個Socket串連時,同時建立一個新線程對該Socket進行單獨通訊(採用阻塞的方式通訊)。這種方式具有很高的響應速度,並且控制起來也很簡單,在串連數較少的時候非常有效,但是如果對每一個串連都產生一個線程的無疑是對系統資源的一種浪費,如果串連數較多將會出現資源不足的情況。 

另一種較高效的做法是:伺服器端儲存一個Socket串連列表,然後對這個列表進行輪詢,如果發現某個Socket連接埠上有資料可讀時(讀就緒),則調用該socket串連的相應讀操作;如果發現某個 Socket連接埠上有資料可寫時(寫就緒),則調用該socket串連的相應寫操作;如果某個連接埠的Socket串連已經中斷,則調用相應的析構方法關閉該連接埠。這樣能充分利用伺服器資源,效率得到了很大提高。 

傳統的阻塞式IO,每個串連必須要開一個線程來處理,並且沒處理完線程不能退出。 

非阻塞式IO,由於基於反應器模式,用於事件多路分離和指派的體繫結構模式,所以可以利用線程池來處理。事件來了就處理,處理完了就把線程歸還。而傳統阻塞方式不能使用線程池來處理,假設當前有10000個串連,非阻塞方式可能用1000個線程的線程池就搞定了,而傳統阻塞方式就需要開10000個來處理。如果串連數較多將會出現資源不足的情況。非阻塞的核心優勢就在這裡。 

為什麼會這樣,下面就對他們做進一步細緻具體的分析: 

首先,我們來分析傳統阻塞式IO的瓶頸在哪裡。在串連數不多的情況下,傳統IO編寫容易方便使用。但是隨著串連數的增多,問題傳統IO就不行了。因為前面說過,傳統IO處理每個串連都要消耗 一個線程,而程式的效率當線程數不多時是隨著線程數的增加而增加,但是到一定的數量之後,是隨著線程數的增加而減少。這裡我們得出結論,傳統阻塞式IO的瓶頸在於不能處理過多的串連。 

然後,非阻塞式IO的出現的目的就是為瞭解決這個瓶頸。而非阻塞式IO是怎麼實現的呢?非阻塞IO處理串連的線程數和串連數沒有聯絡,也就是說處理10000個串連非阻塞IO不需要10000個線程,你可以用1000個也可以用2000個線程來處理。因為非阻塞IO處理串連是非同步。當某個串連發送請求到伺服器,伺服器把這個串連請求當作一個請求"事件",並把這個"事件"分配給相應的函數處理。我們可以把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就可以非同步處理多個事件。而阻塞式IO的線程的大部分時間都浪費在等待請求上了。 
[b]引用自:http://javag.javaeye.com

阻塞式IO就是在進行讀寫的時候調用了某個方法,如read()或write()方法 
在該方法執行完之前,會一直等待,直到該方法執行完畢。所謂阻塞式IO流,就是指在從資料流當中讀寫資料的的時候,阻塞當前線程,直到IO流可以重新使用為止,你也可以使用流的avaliableBytes()函數看看當前流當中有多少位元組可以讀取,這樣就不會再阻塞了。

Java code
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;

public class ChannelInputStream extends InputStream {

   private ReadableByteChannel channel;

   public ChannelInputStream(ReadableByteChannel channel) throws IllegalArgumentException {
     if (channel == null) {
       throw new IllegalArgumentException("The readable byte channel is null");
     }

     this.channel = channel;
   }

   public int read() throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(1);
     int result = channel.read(buffer);
     if (result != -1) {
       buffer.flip();
       result = (int) buffer.get();
       buffer.clear();
     }
     return result;
   }

   public int read(byte b[]) throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(b.length);
     int result = channel.read(buffer);
     if (result != -1) {
       buffer.flip();
       buffer.get(b, 0, result);
       buffer.clear();
     }
     return result;
   }

   public int read(byte b[], int off, int len) throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(b.length);
     int result = channel.read(buffer);
     if (result != -1) {
       buffer.flip();
       buffer.get(b, off, len > result ? result : len);
       buffer.clear();
     }
     return result;
   }

   public void close() throws IOException {
     channel.close();
   }
}

Java中的阻塞和非阻塞IO包各自的優劣思考 

NIO 設計背後的基石:反應器模式,用於事件多路分離和指派的體繫結構模式。 

反應器(Reactor):用於事件多路分離和指派的體繫結構模式 

通常的,對一個檔案描述符指定的檔案或裝置, 有兩種工作方式: 阻塞 與非阻塞 。所謂阻塞方式的意思是指, 當試圖對該檔案描述符進行讀寫時, 如果當時沒有東西可讀,或者暫時不可寫, 程式就進入等待 狀態, 直到有東西可讀或者可寫為止。而對於非阻塞狀態, 如果沒有東西可讀, 或者不可寫, 讀寫函數馬上返回, 而不會等待 。 

一種常用做法是:每建立一個Socket串連時,同時建立一個新線程對該Socket進行單獨通訊(採用阻塞的方式通訊)。這種方式具有很高的響應速度,並且控制起來也很簡單,在串連數較少的時候非常有效,但是如果對每一個串連都產生一個線程的無疑是對系統資源的一種浪費,如果串連數較多將會出現資源不足的情況。 

另一種較高效的做法是:伺服器端儲存一個Socket串連列表,然後對這個列表進行輪詢,如果發現某個Socket連接埠上有資料可讀時(讀就緒),則調用該socket串連的相應讀操作;如果發現某個 Socket連接埠上有資料可寫時(寫就緒),則調用該socket串連的相應寫操作;如果某個連接埠的Socket串連已經中斷,則調用相應的析構方法關閉該連接埠。這樣能充分利用伺服器資源,效率得到了很大提高。 

傳統的阻塞式IO,每個串連必須要開一個線程來處理,並且沒處理完線程不能退出。 

非阻塞式IO,由於基於反應器模式,用於事件多路分離和指派的體繫結構模式,所以可以利用線程池來處理。事件來了就處理,處理完了就把線程歸還。而傳統阻塞方式不能使用線程池來處理,假設當前有10000個串連,非阻塞方式可能用1000個線程的線程池就搞定了,而傳統阻塞方式就需要開10000個來處理。如果串連數較多將會出現資源不足的情況。非阻塞的核心優勢就在這裡。 

為什麼會這樣,下面就對他們做進一步細緻具體的分析: 

首先,我們來分析傳統阻塞式IO的瓶頸在哪裡。在串連數不多的情況下,傳統IO編寫容易方便使用。但是隨著串連數的增多,問題傳統IO就不行了。因為前面說過,傳統IO處理每個串連都要消耗 一個線程,而程式的效率當線程數不多時是隨著線程數的增加而增加,但是到一定的數量之後,是隨著線程數的增加而減少。這裡我們得出結論,傳統阻塞式IO的瓶頸在於不能處理過多的串連。 

然後,非阻塞式IO的出現的目的就是為瞭解決這個瓶頸。而非阻塞式IO是怎麼實現的呢?非阻塞IO處理串連的線程數和串連數沒有聯絡,也就是說處理10000個串連非阻塞IO不需要10000個線程,你可以用1000個也可以用2000個線程來處理。因為非阻塞IO處理串連是非同步。當某個串連發送請求到伺服器,伺服器把這個串連請求當作一個請求"事件",並把這個"事件"分配給相應的函數處理。我們可以把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就可以非同步處理多個事件。而阻塞式IO的線程的大部分時間都浪費在等待請求上了。 
[b]引用自:http://javag.javaeye.com

阻塞式IO就是在進行讀寫的時候調用了某個方法,如read()或write()方法 
在該方法執行完之前,會一直等待,直到該方法執行完畢。所謂阻塞式IO流,就是指在從資料流當中讀寫資料的的時候,阻塞當前線程,直到IO流可以重新使用為止,你也可以使用流的avaliableBytes()函數看看當前流當中有多少位元組可以讀取,這樣就不會再阻塞了。

Java code
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;

public class ChannelInputStream extends InputStream {

   private ReadableByteChannel channel;

   public ChannelInputStream(ReadableByteChannel channel) throws IllegalArgumentException {
     if (channel == null) {
       throw new IllegalArgumentException("The readable byte channel is null");
     }

     this.channel = channel;
   }

   public int read() throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(1);
     int result = channel.read(buffer);
     if (result != -1) {
       buffer.flip();
       result = (int) buffer.get();
       buffer.clear();
     }
     return result;
   }

   public int read(byte b[]) throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(b.length);
     int result = channel.read(buffer);
     if (result != -1) {
       buffer.flip();
       buffer.get(b, 0, result);
       buffer.clear();
     }
     return result;
   }

   public int read(byte b[], int off, int len) throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(b.length);
     int result = channel.read(buffer);
     if (result != -1) {
       buffer.flip();
       buffer.get(b, off, len > result ? result : len);
       buffer.clear();
     }
     return result;
   }

   public void close() throws IOException {
     channel.close();
   }
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.