NIO 多線程處理異步隊列

本文使用java的NIO簡單實現server-client模式,處理異步隊列。

緩存隊列類

public class Buffer {
    private static Queue<Object> queue = new LinkedList<Object>();

    private static int INITSIZE = 2;

    private Lock mutex;

    private Condition condition;

    private Buffer(){
        mutex = new ReentrantLock();
        condition = mutex.newCondition();
    }

    public static Buffer getIntance(){
        return QueueBuffer.instance;
    }

    static class QueueBuffer{
        private static Buffer instance = new Buffer();
    }

    public void setInitSize(int size){
        INITSIZE = size;
    }

    public void produce(String msg){
        mutex.lock();
        try {
            while(queue.size() >= INITSIZE ){
                System.out.println("queue wait to consume");
                condition.await();
            }

            queue.offer(msg);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            condition.signalAll();
            mutex.unlock();
        }

    }

    public Object consume(){
        mutex.lock();
        try {
            while (queue.size() == 0) {
                System.out.println("queue wait to produce");
                condition.await();
            }

            return queue.poll();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } finally {
            condition.signalAll();
            mutex.unlock();
        }
    }

    public int getQueueSize(){
        return queue.size();
    }
}

任務類

public class Task implements Runnable{

    private static ConcurrentLinkedQueue<SelectionKey> clq = new ConcurrentLinkedQueue<>();

    private NIOServer server;

    public Task(NIOServer server){
        this.server = server;
    }

    public static void push(SelectionKey key){
        clq.add(key);
    }

    @Override
    public void run() {
        try {
                SelectionKey key = clq.poll();
                server.msgHandle(key);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

服務端類

public class NIOServer {
    private ServerSocketChannel serverSocketChannel;

    int port = 8080;

    private Selector selector;

    ByteBuffer recBuffer = ByteBuffer.allocate(1024);

    ByteBuffer sendBuffer = ByteBuffer.allocate(1024);

    Map<SelectionKey, String> clientMsgs = new HashMap<>();

    private static int client_no = 0;

    ExecutorService serviceExecutor = Executors.newFixedThreadPool(10);

    Task task = null;

    public NIOServer(int port) throws IOException {
        this.port = port;
        serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(this.port));
        serverSocketChannel.configureBlocking(false);
        selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("init finish");
        task = new Task(this);
    }

    public void listen() throws IOException {
        while (true) {
            System.out.println("server scanning");
            int event = selector.select();
            if (event > 0) {
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    process(key);
                }
            }
        }
    }

    private void process(SelectionKey selectionKey) {
        SocketChannel client = null;
        try {
            if (selectionKey.isValid() && selectionKey.isAcceptable()) {
                client = serverSocketChannel.accept();
                ++client_no;
                client.configureBlocking(false);
                client.register(selector, SelectionKey.OP_READ);
            } else if (selectionKey.isValid() && selectionKey.isReadable()) {
                readHandle(selectionKey);
            } else if (selectionKey.isValid() && selectionKey.isWritable()) {
                if (clientMsgs.containsKey(selectionKey)) {
                    writeMsgHanle(selectionKey);
                }
            }
        } catch (Exception e) {
            selectionKey.cancel();
            try {
                selectionKey.channel().close();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

        }

    }

    private void readHandle(SelectionKey selectionKey) throws IOException, InterruptedException {
        SocketChannel client;
        client = (SocketChannel) selectionKey.channel();
        int len = 0;
        while ((len = client.read(recBuffer)) > 0) {
            recBuffer.flip();
            String sb = new String(recBuffer.array(), 0, len);
            clientMsgs.put(selectionKey, sb.toString());
            System.out.println("Thread:" + Thread.currentThread().getId() + ",NO." + client_no + " client send msg:"
                    + sb.toString());
            recBuffer.clear();

        }
        Task.push(selectionKey);
        serviceExecutor.execute(task);
    }

    public void msgHandle(SelectionKey key) throws IOException {
        String msg = clientMsgs.get(key);
        String serverMsg = null;
        if (msg != null && !"".equals(msg)) {
            if (msg.contains("add")) {
                msg = msg.substring(msg.indexOf("add") + 4);
                Buffer.getIntance().produce(msg);
                serverMsg = "server:add " + msg + " to queue successfully";
            } else if (msg.contains("poll")) {
                String consumeMsg = (String) Buffer.getIntance().consume();
                serverMsg = "server:remove " + consumeMsg + " from queue successfully";
            } else if (msg.contains("size")) {
                serverMsg = "server:size is " + Buffer.getIntance().getQueueSize();
            } else {
                serverMsg = "server:no such command";
            }
        } else {
            serverMsg = "server:blank message";
        }
        clientMsgs.put(key,serverMsg);
        writeMsgHanle(key);
    }

    private void writeMsgHanle(SelectionKey key) throws IOException {
        String msg = clientMsgs.get(key);
        SocketChannel client;
        sendBuffer.clear();
        sendBuffer.put(msg.getBytes());
        client = (SocketChannel) key.channel();
        sendBuffer.flip();// write in range of text length
        while (sendBuffer.hasRemaining()) {
            client.write(sendBuffer);
        }
        key.interestOps(SelectionKey.OP_READ);
    }

    public static void main(String[] args) throws IOException {
        new NIOServer(8080).listen();
    }
}

客戶端類

public class NIOClient {
    private SocketChannel client;

    private Selector selector;

    private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);

    private ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);

    public NIOClient(String ip, int port) throws IOException{
        client = SocketChannel.open();
        selector = Selector.open();
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_READ);
        client.connect(new InetSocketAddress(ip, port));
        while (!client.finishConnect()) {
            System.out.println("finish connect");
        }
    }

    public void run(){
        while(true){
            try {
                while (!writeHandle()) {
                    System.out.println("please input a not empty command");
                }
                int event = selector.select();
                if (event > 0) {
                    Set<SelectionKey> keys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = keys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        if (key.isValid() && key.isReadable()) {
                            readHandle(key);
                        }
                        iterator.remove();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (client.isOpen()) {
                    try {
                        client.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }

    private void readHandle(SelectionKey key) throws IOException {
        SocketChannel scChannel = null;
        scChannel = (SocketChannel) key.channel();
        receiveBuffer.clear();
        int len = 0;
        if ((len = scChannel.read(receiveBuffer)) > 0) {
            receiveBuffer.flip();
            String msg = new String(receiveBuffer.array(),0,len);
            System.out.println(msg);
        }
    }

    public boolean writeHandle() throws IOException{
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();
        if (line != null && line.length() > 0) {
            sendBuffer.clear();
            sendBuffer.put(line.getBytes());
            sendBuffer.flip();
            while (sendBuffer.hasRemaining()) {
                client.write(sendBuffer);
            }
            return true;
        }else{
            return false;
        }
    }

    public static void main(String[] args) throws IOException {
        new NIOClient("127.0.0.1", 8080).run();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章