在 Java 中,线程的实现是较量重量级的,以是线程的启动可能烧毁是很耗损处事器的资源的,纵然行使线程池来实现,行使上述传统的 Socket 方法,当毗连数极具上升也会带来机能瓶颈,缘故起因是线程的上线文切换开销会在高并发的时辰浮现的很明明,而且以上操纵方法照旧同步阻塞式的编程,机能题目在高并发的时辰就会浮现的尤为明明。
以上的流程,如下图:
4.2 NIO 多路复用
介于以上高并发的题目,NIO 的多路复用成果就显自得义不凡了。
NIO 是操作了单线程轮询变乱的机制,通过高效地定位停当的 Channel,来抉择做什么,仅仅 select 阶段是阻塞的,可以有用停止大量客户端毗连时,频仍线程切换带来的题目,应用的扩展手段有了很是大的进步。
- // NIO 多路复用
- ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4,
- 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
- threadPool.execute(new Runnable() {
- @Override
- public void run() {
- try (Selector selector = Selector.open();
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();) {
- serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), port));
- serverSocketChannel.configureBlocking(false);
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- while (true) {
- selector.select(); // 阻塞守候停当的Channel
- Set<SelectionKey> selectionKeys = selector.selectedKeys();
- Iterator<SelectionKey> iterator = selectionKeys.iterator();
- while (iterator.hasNext()) {
- SelectionKey key = iterator.next();
- try (SocketChannel channel = ((ServerSocketChannel) key.channel()).accept()) {
- channel.write(Charset.defaultCharset().encode("你好,天下"));
- }
- iterator.remove();
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- });
- // Socket 客户端(吸取信息并打印)
- try (Socket cSocket = new Socket(InetAddress.getLocalHost(), port)) {
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
- bufferedReader.lines().forEach(s -> System.out.println("NIO 客户端:" + s));
- } catch (IOException e) {
- e.printStackTrace();
- }
- 起首,通过 Selector.open() 建设一个 Selector,作为相同调治员的脚色;
- 然后,建设一个 ServerSocketChannel,而且向 Selector 注册,通过指定 SelectionKey.OP_ACCEPT,汇报调治员,它存眷的是新的毗连哀求;
- 为什么我们要明晰设置非阻塞模式呢?这是由于阻塞模式下,注册操纵是不应承的,会抛出 IllegalBlockingModeException 非常;
- Selector 阻塞在 select 操纵,当有 Channel 产生接入哀求,就会被叫醒;
下面的图,可以有用的声名 NIO 复用的流程:
就这样 NIO 的多路复用就大大晋升了处事器端相应高并发的手段。
4.3 AIO 版 Socket 实现
Java 1.7 提供了 AIO 实现的 Socket 是这样的,如下代码:
- // AIO线程复用版
- Thread sThread = new Thread(new Runnable() {
- @Override
- public void run() {
- AsynchronousChannelGroup group = null;
- try {
- group = AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(4));
- AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group).bind(new InetSocketAddress(InetAddress.getLocalHost(), port));
- server.accept(null, new CompletionHandler<AsynchronousSocketChannel, AsynchronousServerSocketChannel>() {
- @Override
- public void completed(AsynchronousSocketChannel result, AsynchronousServerSocketChannel attachment) {
- server.accept(null, this); // 吸取下一个哀求
- try {
- Future<Integer> f = result.write(Charset.defaultCharset().encode("你好,天下"));
- f.get();
- System.out.println("处事端发送时刻:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
- result.close();
- } catch (InterruptedException | ExecutionException | IOException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) {
- }
- });
- group.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
- } catch (IOException | InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- sThread.start();
- // Socket 客户端
- AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
- Future<Void> future = client.connect(new InetSocketAddress(InetAddress.getLocalHost(), port));
- future.get();
- ByteBuffer buffer = ByteBuffer.allocate(100);
- client.read(buffer, null, new CompletionHandler<Integer, Void>() {
- @Override
- public void completed(Integer result, Void attachment) {
- System.out.println("客户端打印:" + new String(buffer.array()));
- }
- @Override
- public void failed(Throwable exc, Void attachment) {
- exc.printStackTrace();
- try {
- client.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- });
- Thread.sleep(10 * 1000);
五、总结 (编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|