最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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是一個簡單卻強大的概念,它是指在多個緩沖區(qū)上實現(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ū)。這是一個很大
的進步,因為減少或避免了緩沖區(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)

選擇鍵是選擇器的重點內(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()
}

選擇鍵維護了通道和選擇器之間的關(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)閉時,所有鍵都會被清理掉。

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

感興趣的事件集合interestOps()

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

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

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

就緒的操作集合readyOps()

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

示范選擇器的使用

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

單選擇器單線程

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);
 //如果是阻塞通道進行注冊,會拋出 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 通道概念選擇器使用示例詳解的詳細內(nèi)容,更多關(guān)于Java NIO 通道選擇器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何利用@PreAuthorize注解自定義權(quán)限校驗

    如何利用@PreAuthorize注解自定義權(quán)限校驗

    通過使用@PreAuthorize注解實現(xiàn)開放接口的權(quán)限校驗,具體步驟包括開啟全局方法安全、編寫自定義鑒權(quán)方法、創(chuàng)建自定義異常類、在統(tǒng)一異常處理類中捕獲異常并處理,最后在需要鑒權(quán)的接口上貼上注解
    2024-12-12
  • Java編程IP地址和數(shù)字相互轉(zhuǎn)換代碼示例

    Java編程IP地址和數(shù)字相互轉(zhuǎn)換代碼示例

    這篇文章主要介紹了Java編程IP地址和數(shù)字相互轉(zhuǎn)換代碼示例,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • MybatisPlus自動填充時間的配置類實現(xiàn)

    MybatisPlus自動填充時間的配置類實現(xiàn)

    本文介紹了如何在MyBatis-Plus中實現(xiàn)自動填充時間的功能,通過實現(xiàn)MetaObjectHandler接口,重寫insertFill()和updateFill()方法,分別在插入和更新時填充創(chuàng)建時間和更新時間,感興趣的可以了解一下
    2024-12-12
  • springboot對數(shù)據(jù)庫密碼加密的實現(xiàn)

    springboot對數(shù)據(jù)庫密碼加密的實現(xiàn)

    這篇文章主要介紹了springboot對數(shù)據(jù)庫密碼加密的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Spring?boot?使用QQ郵箱進行一個驗證登入功能

    Spring?boot?使用QQ郵箱進行一個驗證登入功能

    這篇文章主要介紹了Spring?boot?使用QQ郵箱進行一個驗證登入,主要包括qq郵箱開啟權(quán)限和創(chuàng)建發(fā)送驗證碼的請求Controller,本文通過示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-10-10
  • java基于servlet的文件異步上傳

    java基于servlet的文件異步上傳

    本篇文章主要介紹了java基于servlet的文件異步上傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2016-10-10
  • Java雙重MD5加密實現(xiàn)安全登錄

    Java雙重MD5加密實現(xiàn)安全登錄

    MD5對密碼進行加密存儲是常見的一種加密方式,本文主要介紹了Java雙重MD5加密實現(xiàn)安全登錄,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • MyBatis中批量插入和批量更新的實現(xiàn)方法詳解

    MyBatis中批量插入和批量更新的實現(xiàn)方法詳解

    這篇文章主要介紹了MyBatis中批量插入和批量更新的實現(xiàn)方法,在日常開發(fā)中有時候需要從A數(shù)據(jù)庫提取大量數(shù)據(jù)同步到B系統(tǒng),這種情況自然是需要批量操作才行,感興趣想要詳細了解可以參考下文
    2023-05-05
  • Java中Map實現(xiàn)線程安全的3種方式

    Java中Map實現(xiàn)線程安全的3種方式

    本文主要介紹了Java中Map實現(xiàn)線程安全的3種方式,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • SpringBoot配置Clickhouse的示例代碼

    SpringBoot配置Clickhouse的示例代碼

    這篇文章主要介紹了SpringBoot配置Clickhouse的示例代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考價值,需要的朋友可以參考下
    2022-02-02

最新評論

潢川县| 榆林市| 循化| 英德市| 北川| 呼和浩特市| 呼图壁县| 乌恰县| 青海省| 武穴市| 铜梁县| 亚东县| 广灵县| 蒙山县| 刚察县| 锡林郭勒盟| 元谋县| 海宁市| 广宁县| 辉南县| 金乡县| 富源县| 吉木萨尔县| 大庆市| 东乌珠穆沁旗| 宽甸| 贡山| 汤阴县| 罗田县| 湖南省| 梓潼县| 金寨县| 安义县| 丽水市| 和硕县| 双峰县| 将乐县| 河西区| 吴川市| 墨玉县| 陆良县|