欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?NIO?通道概念選擇器使用示例詳解

 更新時間:2023年10月27日 10:50:29   作者:lane  
這篇文章主要為大家介紹了Java?NIO?通道概念選擇器使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Java NIO通道

通道相當(dāng)于一個傳遞物品的管子,兩邊都可以往對面?zhèn)鬟f東西。

有哪些通道?

對應(yīng)文件IO和網(wǎng)絡(luò)IO,通道也分為一個FileChannel和三個socket通道(SocketChannel、ServerSocketChannel和DatagramChannel)

基礎(chǔ)一般情況下,一個通道必然關(guān)聯(lián)著一個文件描述符或者是文件句柄。

通道可以是單向的,也可以是雙向的(讀寫)。

socket通道可以是阻塞的或非阻塞的,F(xiàn)ileChannel只支持阻塞模式。

Scatter和Gather 發(fā)散和匯聚

從字面理解,通道支持多個緩沖區(qū)同時讀寫。這樣能夠充分利用現(xiàn)代操作系統(tǒng)多核CPU功能,同時填充或排干多個緩沖區(qū)。

Scatter/Gather是一個簡單卻強(qiáng)大的概念,它是指在多個緩沖區(qū)上實(shí)現(xiàn)一個簡單的 I/O 操作。對于一個 write 操作而言,數(shù)據(jù)是從幾個緩沖區(qū)按順序抽?。ǚQ為 gather)并沿著通道發(fā)送的。

緩沖區(qū)本身并不需要具備這種gather 的能力(通常它們也沒有此能力)。該 gather 過程的效果就好比全部緩沖區(qū)的內(nèi)容被連結(jié)起來,并在發(fā)送數(shù)據(jù)前存放到一個大的緩沖區(qū)中。對于 read 操作而言,從
通道讀取的數(shù)據(jù)會按順序被散布(稱為 scatter)到多個緩沖區(qū),將每個緩沖區(qū)填滿直至通道中的數(shù)據(jù)或者緩沖區(qū)的最大空間被消耗完。

大多數(shù)現(xiàn)代操作系統(tǒng)都支持本地矢量 I/O(native vectored I/O)。當(dāng)您在一個通道上請求一個Scatter/Gather 操作時,該請求會被翻譯為適當(dāng)?shù)谋镜卣{(diào)用來直接填充或抽取緩沖區(qū)。這是一個很大
的進(jìn)步,因?yàn)闇p少或避免了緩沖區(qū)拷貝和系統(tǒng)調(diào)用。Scatter/Gather 應(yīng)該使用直接的 ByteBuffers 以從本地 I/O 獲取最大性能優(yōu)勢。

Java NIO 選擇器

從最基礎(chǔ)的層面上來看,選擇器提供了問詢通道是否就緒操作I/O的能力,選擇器可以監(jiān)控注冊在上面的多個通道,通道注冊時會返回選擇鍵(記錄通道與選擇器之間的關(guān)聯(lián)關(guān)系),選擇器管理者這些注冊的鍵、和就緒狀態(tài)鍵的集合

SelectableChannel

所有繼承SelectableChannel的通道都可以在選擇器中注冊,F(xiàn)ileChannel沒有繼承這個類,所以無法使用選擇器

選擇鍵(SelectionKey)

選擇鍵是選擇器的重點(diǎn)內(nèi)容,選擇器就緒的通道通過返回選擇鍵集合來通知

public abstract class SelectionKey {
    public static final int OP_READ
    public static final int OP_WRITE
    public static final int OP_CONNECT
    public static final int OP_ACCEPT
    public abstract SelectableChannel channel();
    public abstract Selector selector();
    public abstract void cancel();
    public abstract boolean isValid();
    public abstract int interestOps();
    public abstract void interestOps(int ops);
    public abstract int readyOps();
    public final boolean isReadable()
    public final boolean isWritable()
    public final boolean isConnectable()
    public final boolean isAcceptable()
    public final Object attach(Object ob)
    public final Object attachment()
}

選擇鍵維護(hù)了通道和選擇器之間的關(guān)聯(lián),可以通過選擇鍵獲取Channel或Selector,鍵對象表示一種特殊的關(guān)聯(lián)關(guān)系,當(dāng)這種關(guān)系需要終止時,可以調(diào)用cancel()方法取消,調(diào)用這個方法時,不會立即被取消,而是將這個鍵放到被取消的集合里,當(dāng)Selector下次調(diào)用select()方法時會真正被清理掉。當(dāng)通道關(guān)閉時,選擇鍵會自動被取消,當(dāng)選擇器關(guān)閉時,所有鍵都會被清理掉。

一個選擇器鍵包含有兩個準(zhǔn)備好的操作集合,包括感興趣的事件集合instrest和就緒的操作集合ready,通過掩碼保存

感興趣的事件集合interestOps()

通常一個鍵的instrest注冊時就已經(jīng)確認(rèn),但是可以在注冊后通過interestOps(newOps)傳入一個新的ops來改變這個值

channel.register(this.selector, SelectionKey.OP_READ);

上面的代碼注冊的鍵interest包含read事件,可以在對通道IO異步處理時,改變這個ops來臨時取消對read事件的關(guān)注,以防止重復(fù)處理未處理完的通道

就緒的操作集合readyOps()

通過這個方法返回就緒的操作,isReadable( ),isWritable( ),isConnectable( ), 和isAcceptable( )用來判斷這些操作是否就緒,進(jìn)行下一步的處理

示范選擇器的使用

下面列舉兩個示例來示范選擇器的使用

單選擇器單線程

public abstract class AbstractNioServer {
    protected final static String CHARSET = "utf-8";
 protected String ip;
 protected Integer port;
 protected Selector selector;
 public AbstractNioServer(String ip, Integer port) {
        this.ip = ip;
 this.port = port;
 }
    /**
 * 客戶端連接請求
 *
 * @param key
 */
 protected abstract void accept(SelectionKey key) throws IOException;
 /**
 * 讀取數(shù)據(jù)
 *
 * @param key
 */
 protected abstract void read(SelectionKey key) throws IOException;
 /**
 * 初始化服務(wù)器
 *
 * @throws IOException
 */ public void init() throws IOException {
        //設(shè)置服務(wù)器地址端口
 SocketAddress address = new InetSocketAddress(this.ip, this.port);
 //創(chuàng)建服務(wù)端通道
 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
 //綁定服務(wù)器地址
 serverSocketChannel.bind(address);
 //設(shè)置為非阻塞模式
 serverSocketChannel.configureBlocking(false);
 //創(chuàng)建一個選擇器
 this.selector = Selector.open();
 //將服務(wù)器通道注冊到選擇器中,ServerSocketChannel只支持accept事件注冊,validOps返回16
 serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
 }
    public void start() throws IOException {
        this.init();
 while (true) {
            int count = this.selector.select();
 if (count == 0) {
                //沒有就緒的選擇鍵
 continue;
 }
            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
 while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
 if (!key.isValid()) {
                    continue;
 }
                if (key.isAcceptable()) {
                    //連接請求
 accept(key);
 } else if (key.isReadable()) {
                    //修改鍵的感興趣事件,防止被 select 重復(fù)調(diào)用,處理完事件后及時恢復(fù)
 key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
 //讀取消息
 read(key);
 }
                iterator.remove();
 }
        }
    }
    /**
 * 恢復(fù)鍵的感興趣事件
 * @param key
 */
 protected void resumeInterOpsRead(SelectionKey key) {
        //還原key的感興趣事件
 key.interestOps(key.interestOps() | SelectionKey.OP_READ);
 //喚醒selector的select事件
 key.selector().wakeup();
 }
}
public class SingleNioServer extends AbstractNioServer {
    public static void main(String[] args) {
        SingleNioServer server = new SingleNioServer("127.0.0.1", 1008);
 try {
            server.start();
 } catch (IOException e) {
            e.printStackTrace();
 }
    }
    public SingleNioServer(String ip, Integer port) {
        super(ip, port);
 }
    @Override
 protected void accept(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
 //SocketChannel支持 read、write、connect 事件注冊,validOps返回13=1+4+8
 SocketChannel channel = serverChannel.accept();
 if (channel == null) {
            return;
 }
        System.out.println("新的連接請求");
 channel.configureBlocking(false);
 //如果是阻塞通道進(jìn)行注冊,會拋出 IllegalBlockingModeException 異常
 channel.register(this.selector, SelectionKey.OP_READ);
 }
    @Override
 protected void read(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
 try {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
 int len = channel.read(buffer);
 buffer.flip();
 if (len > 0) {
                String str = Charset.forName(CHARSET).decode(buffer).toString();
 System.out.println("客戶端消息:" + str);
 String msg = "消息已收到";
 byte[] sendData = msg.getBytes(CHARSET);
 ByteBuffer sendBuffer = ByteBuffer.wrap(sendData);
 channel.write(sendBuffer);
 super.resumeInterOpsRead(key);
 } else if (len == -1) {
                System.out.println("socket client close");
 key.cancel();
 channel.close();
 }
        } catch (IOException ex) {
            key.cancel();
 channel.close();
 }
    }
}

單選擇器多線程

public class MulitpleNioServer extends AbstractNioServer {
    public static void main(String[] args) throws IOException {
        MulitpleNioServer server = new MulitpleNioServer("127.0.0.1", 1008);
 server.start();
 }
    /**
 * 線程池
 */
 private ExecutorService executorService = Executors.newFixedThreadPool(5);
 public MulitpleNioServer(String ip, Integer port) {
        super(ip, port);
 }
    @Override
 protected void accept(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
 //SocketChannel支持 read、write、connect 事件注冊,validOps返回13=1+4+8
 SocketChannel channel = serverChannel.accept();
 System.out.println("新的連接請求");
 channel.configureBlocking(false);
 channel.register(this.selector, SelectionKey.OP_READ);
 }
    @Override
 protected void read(SelectionKey key) throws IOException {
        executorService.submit(new Runnable() {
            @Override
 public void run() {
                readData(key);
 }
        });
 }
    private void readData(SelectionKey key) {
        SocketChannel channel = (SocketChannel) key.channel();
 try {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
 if (channel.isOpen()) {
                if (channel.isConnected()) {
                    int len = channel.read(buffer);
 buffer.flip();
 if (len > 0) {
                        String str = Charset.forName(CHARSET).decode(buffer).toString();
 System.out.println("客戶端消息:" + str);
 String msg = "消息已收到";
 byte[] sendData = msg.getBytes(CHARSET);
 ByteBuffer sendBuffer = ByteBuffer.wrap(sendData);
 channel.write(sendBuffer);
 } else if (len == -1) {
                        System.out.println("socket client close1");
 key.cancel();
 channel.close();
 }
                    super.resumeInterOpsRead(key);
 }
            }
        } catch (IOException ex) {
            System.out.println("client is close2");
 key.cancel();
 try {
                channel.close();
 } catch (IOException e) {
                e.printStackTrace();
 }
        }
    }
}

以上就是Java NIO 通道概念選擇器使用示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Java NIO 通道選擇器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • IDEA中Web項(xiàng)目控制臺亂碼的問題及解決方法

    IDEA中Web項(xiàng)目控制臺亂碼的問題及解決方法

    這篇文章主要介紹了IDEA中Web項(xiàng)目控制臺亂碼的問題及解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java多線程之悲觀鎖與樂觀鎖

    Java多線程之悲觀鎖與樂觀鎖

    這篇文章主要為大家詳細(xì)介紹了Java悲觀鎖與樂觀鎖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • mybatis如何批量更新list對象

    mybatis如何批量更新list對象

    這篇文章主要介紹了mybatis如何批量更新list對象問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 淺析Java的Hibernate框架中的緩存和延遲加載機(jī)制

    淺析Java的Hibernate框架中的緩存和延遲加載機(jī)制

    這篇文章主要介紹了Java的Hibernate框架中的緩存和延遲加載機(jī)制,Hibernate是注明的Java下SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-11-11
  • Mybatis配置錯誤:java.lang.ExceptionInInitializerError

    Mybatis配置錯誤:java.lang.ExceptionInInitializerError

    這篇文章主要介紹了Mybatis配置錯誤:java.lang.ExceptionInInitializerError的相關(guān)資料,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Spring配置文件解析之BeanDefinitionParserDelegate詳解

    Spring配置文件解析之BeanDefinitionParserDelegate詳解

    這篇文章主要介紹了Spring配置文件解析之BeanDefinitionParserDelegate詳解,對于Spring的配置文件的解析處理操作是在BeanDefinitionParserDelegate中進(jìn)行處理操作,接下來我們簡單介紹一下BeanDefinitionParserDelegate所做的處理操作,需要的朋友可以參考下
    2024-02-02
  • 從零搭建Spring Boot腳手架整合OSS作為文件服務(wù)器的詳細(xì)教程

    從零搭建Spring Boot腳手架整合OSS作為文件服務(wù)器的詳細(xì)教程

    這篇文章主要介紹了從零搭建Spring Boot腳手架整合OSS作為文件服務(wù)器的詳細(xì)教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java一個簡單的紅包生成算法

    Java一個簡單的紅包生成算法

    今天小編就為大家分享一篇關(guān)于Java一個簡單的紅包生成算法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • MyBatis-Plus實(shí)現(xiàn)條件查詢的三種格式例舉詳解

    MyBatis-Plus實(shí)現(xiàn)條件查詢的三種格式例舉詳解

    本文主要介紹了MyBatis-Plus三中條件查詢格式的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08

最新評論