analyse Java NIO base et la compréhension de l'utilisation de

Je il y a quelque temps un blog programmation réseau java - données parallèles multi-thread émetteur - récepteur résume la pratique parallèle de l' émetteur - récepteur entre le serveur et le client. Le principe est très simple, qui est, pour un seul client, la portée des services deux fils sont responsables des opérations de lecture et d' écriture, puis enfilez reste bloqué en attente de lecture et d'écriture exécution.

En fait, ce modèle est très mauvais. Parce que chaque client sur les besoins du serveur d'occuper deux fils, s'il y a 1000 clients, vous devez 2000+ threads. cpu prend beaucoup de temps pour enfiler les changements de contexte, les ressources système sont gaspillées.

Nous voulons réduire le nombre de threads, d'abord résoudre le problème de blocage. Le NIO peut être multiplexé bloquera lecture et écriture à effacement par IO. Couplé avec le pool de threads, vous pouvez obtenir un million de connexions clients avec une petite quantité de soutien du fil.

Quel est le NIO

multiplexage NIO et IO

nom complet java NIO java non bloquant IO. Cela est littéralement IO non bloquante. En fait, le seul non-bloquant ici l'argument macro.

À propos du mode IO, où d'autres ont cité un blog, décrit les différences de plusieurs mode de IO:

Brief IO synchrone, asynchrone IO, les connexions de blocage et les différences entre IO, IO non bloquante

Ce blog ne répétera pas ces derniers, que je veux dire NIO appartiennent à l'un des modèles de multiplexage IO. (Lab a un dos « réseau UNIX de programmation » à l'école pour mettre fin à l'épidémie doit jeter un oeil à cette partie)

Multiplexé modèle IO, il y a un fil de continuer à interroger plusieurs états prise lorsque lu et les événements d'écriture, pour appeler des opérations d'entrées-sorties. Parce qu'il est un fil pour gérer la prise multiple, le système n'a pas besoin de créer un autre fil, le fil de l'entretien, que la prise lorsque vous êtes prêt, utilisera les ressources IO, il réduit considérablement la consommation de ressources.

java NIO s'il y a des canaux de multiples moniteur selector.select d'utilisation () pour parvenir à l'événement, aucun événement a été bloqué, un événement est appelé traitement IO.

trois noyau

  • Channel (canal)
  • Buffer (tampon)
  • Sélecteur (sélecteurs)

Les détails sont comme suit
image

Exemple d'application NIO

lit ici le message au processus du serveur du client, par exemple, décrit l'utilisation de NIO (contenu complet seulement d'entrée, quelle que soit la sortie pour l'instant). Dessiner un organigramme comme indiqué ci-dessous:
image

  1. Et établir un sélecteur de ServerSocketChannel, et l'enregistrement obligatoire, les écoutes client pour une demande de connexion, comme suit:
selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
// 设置为非阻塞
server.configureBlocking(false);
// 绑定本地端口
server.socket().bind(new InetSocketAddress(port));
// 注册客户端连接到达监听
server.register(selector, SelectionKey.OP_ACCEPT);

Mais aussi d'établir readSelector et writeSelector. En fait, le pool de threads est établie à l'avance, ne pas écrire ici pour l'instant.

readSelector = Selector.open();
writeSelector = Selector.open();
  1. canal moniteur, donner au client, et d'établir le SocketChannel, pour surveiller les messages des clients suivants
//select()方法返回已就绪的通道数
if (selector.select() == 0) {
    continue;
}

Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {

    SelectionKey key = iterator.next();
    iterator.remove();

    // 检查当前Key的状态是否是accept的
    // 客户端到达状态
    if (key.isAcceptable()) {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
        // 非阻塞状态拿到客户端连接
        SocketChannel socketChannel = serverSocketChannel.accept();

        try {
            // 客户端构建异步线程
            // 添加同步处理
            //此处代码暂且忽略
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("客户端连接异常:" + e.getMessage());
        }
    }
  1. Le SocketChannel enregistré dans readSelector et writeSelector
/**
*参数分别是:channel,对应的selector,以及
*registerOps:待注册的操作集,这个在后文中有详细解析;
*locker:用于标识同步代码块的状态,是锁定还是可用;
*runnable:执行具体读写操作的类,送给线程池执行;
*map:建立SelectionKey与Runnable映射关系的HashMap。
*/
private static SelectionKey registerSelection(SocketChannel channel, Selector selector,
                                                  int registerOps, AtomicBoolean locker,
                                                  HashMap<SelectionKey, Runnable> map,
                                                  Runnable runnable) {
    synchronized (locker) {
    // 设置锁定状态
    locker.set(true);
    
    try {
        // 唤醒当前的selector,让selector不处于select()状态
        //注册channel时一定要将selector唤醒,否则当前select中没有刚注册的channel
        selector.wakeup();
    
        SelectionKey key = null;
        if (channel.isRegistered()) {
            // 查询是否已经注册过
            key = channel.keyFor(selector);
            if (key != null) {
            //将新的Ops添加进去
                key.interestOps(key.readyOps() | registerOps);
            }
        }
    
        if (key == null) {
            // 注册selector得到Key
            key = channel.register(selector, registerOps);
            // 注册回调
            map.put(key, runnable);
        }
    
        return key;
    } catch (ClosedChannelException e) {
        return null;
    } finally {
        // 解除锁定状态
        locker.set(false);
        try {
            // 通知
            locker.notify();
        } catch (Exception ignored) {
        }
    }
    }
}
  1. Contrôler chaque message de client pour obtenir canal à travers selectionKeys, puis effectue une opération d'entrée
try {
if (readSelector.select() == 0) {
    continue;
}

Set<SelectionKey> selectionKeys = readSelector.selectedKeys();
for (SelectionKey selectionKey : selectionKeys) {
    if (selectionKey.isValid()) {
        //IO处理代码,暂且忽略
    }
}
selectionKeys.clear();
} catch (IOException e) {
e.printStackTrace();
}

Note: Ce sont des fragments de code, il n'y a pas tout à fait ensemble, et omet une partie de l'objet de classe d'appel, appel de méthode et de fonctionnement clé, etc., de la piscine de fil. Mais l'approche de base a été affichée, le reste du blog retourner à remplir la fosse.

Regardez le code ci-dessus, une méthode NIO cognitive est très vague. Les commentaires suivants à la lecture du sélecteur de source classe SelectionKey et les classes, d'approfondir la compréhension de la partie de la méthode.

sélecteur de classe

sélecteur NIO est les classes de base, voici sélecteur de méthode importante:

  • ouvert connexes
    • open () ouvre un sélecteur
    • public abstract boolean isOpen (); déterminer si d'ouverture
public static Selector open() throws IOException {
    return SelectorProvider.provider().openSelector();
}
  • clés liées
    • Set public abstract Clés (); retour tous jeu de clés
    • Set public abstract les selectedKeys (); ensemble de touche de retour a été sélectionné
  • sélectionner
    • Plusieurs méthodes sont les rendements prêts suivants le nombre de canaux, peut être 0;
    • selectNow (), un procédé de non-blocage;
    • SELECT (), est rentré que dans trois cas, un canal est sélectionné ;. Méthode 2 appel de réveil, 3. interruptions de fil.
    • sélectionner (timeout), à sélectionner () une pluralité d'état non bloqué, à savoir, délai d'attente.
  • réveil (), sélectionner la méthode de blocage pour bloquer ascenseur, retourner immédiatement
  • close (), fermer le sélecteur.

classe SelectionKey

Tout est enregistrée dans un sélecteur de canal sont utilisés pour faire référence à un des objets SelectionKey.

Collection opération

  • Opération-set: un ensemble d'opérations, certaines constantes int valeur, représentant divers types d'opérations, touche de sélection comprend un ensemble de deux opérations, jeu d'intérêt, et ensemble prêt-opération
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
  • Série d'intérêt: Set intérêt; tous les canaux un ensemble d'opérations; peut être mis à jour par interestOps (int) Méthode

  • ensemble prêt Fonctionnement: Prêt à fonctionner, de sorte que le canal comprend seulement une opération prête à déclarer, avec ou mis à jour par l'opération sous-jacente, par exemple quand un canal est prêt à lire, l'opération de lecture est ajoutée à la concentration actuelle prête.

méthode Liste

  • canal abstrait SelectableChannel public (): Renvoie les canaux associés à cette touche de sélection, même si cette clé a été annulée, sera de retour encore ;.
  • Sélecteur de sélection public abstract (): Retourne ce sélecteur pour choisir la clé associée, même si cette clé a été annulée, toujours des retours;
  • public abstract boolean isValid (): Cette clé est valide lorsque la clé de détection est annulée, ou le canal est fermé, ou le sélecteur est fermé, cela se traduira par une AbstractSelector.removeKey touche invalide (key), est réglé sur la cause SelectionKey. invalide;
  • public abstract void cancel (): cette touche pour annuler la demande d'enregistrement À son retour avec succès, la clé est invalide, la propriété valide est ajoutée au compteur dans cancelledKeys .cancel sélecteur opération clé est fausse, et exécute selector.cancel (. clé) (clé à venir se joindre à la collecte cancelledkey);
  • interesOps int public abstract (): cet ensemble clé obtenu intér;
  • interestOps publiques abstraites SelectionKey (ops int): cette touche interst à la valeur spécifiée et cela ops ops channel.validOps vérifier si cela ne prend pas en charge le canal actuel, va lancer une exception ;.
  • readyOps int public abstract (): préparez-vous à cet ensemble clé des opérations qui est déjà en place sur les événements de canal en cours ;.
  • finale booléenne isReadable public (): Cette clé est détectée "lire" la préparation de l'événement est équivalent à:.! (readyOps () et OP_READ) = 0; il isWritable (), isConnectable (), isAcceptable ()
  • Objet final attache du public (objet ob): objet donné comme une pièce jointe sur cette touche, peut être transféré de la pluralité d'attache dans une clé événement ops période de validité ;.
  • public final Attachment Object (): Obtient accessoire de fixation d'un canal, vous pouvez alors présent canal (ou est SelectionKey) ont partagé le cycle de vie, mais les données ne sont pas que la transmission de données de prise de fixation dans le réseau.

Enfin terminé, ce blog ne peut être considéré comme une brève introduction de NIO, quelque chose de pas mentionné. Procédé canal et le tampon ne fait pas partie de l'analyse, le pool de threads ne se trouve plus, ainsi que la sortie fonctionner l'ensemble, je ne parle pas. Toujours veulent compléter autant plus détaillé, mais la plus profonde, la connaissance plus vaste, nous ne pouvons renoncer à une partie du contenu, il est donc devenu comme ça maintenant. Si un plan détaillé pour ouvrir plus d'un blog écrit sera mieux.

Je suppose que tu aimes

Origine www.cnblogs.com/buptleida/p/12633675.html
conseillé
Classement