公司做网站的费用计什么科目,物流相关网站,什么是响应式设计,php网站制作工具阻塞VS非阻塞
阻塞 阻塞模式下#xff0c;相关方法都会导致线程暂停。 ServerSocketChannel.accept() 会在没有建立连接的时候让线程暂停 SocketChannel.read()会在没有数据的时候让线程暂停。 阻塞的表现就是线程暂停了#xff0c;暂停期间不会占用CPU#xff0c;但线程…阻塞VS非阻塞
阻塞 阻塞模式下相关方法都会导致线程暂停。 ServerSocketChannel.accept() 会在没有建立连接的时候让线程暂停 SocketChannel.read()会在没有数据的时候让线程暂停。 阻塞的表现就是线程暂停了暂停期间不会占用CPU但线程相当于闲置。 单线程下阻塞方法之间相互影响几乎不能正常工作需要多线程支持。 但多线程下又有新问题。 32 位 jvm 一个线程 320k64 位 jvm 一个线程 1024k如果连接数过多必然导致 OOM并且线程太多反而会因为频繁上下文切换导致性能降低 可以采用线程池技术来减少线程数和线程上下文切换但治标不治本如果有很多连接建立但长时间 inactive会阻塞线程池中所有线程因此不适合长连接只适合短连接 服务器端
这个代码只能每次在连接到时候读取一次连接事件进行遍历其余事件阻塞即使有其他的读写事件也没有反回应。
public class TestSocketChannel {public static void main(String[] args) throws IOException {//开启服务ServerSocketChannel ssc ServerSocketChannel.open();//banssc.bind(new InetSocketAddress(8080));ListSocketChannel channels new ArrayList();while (true) {//等待建立连接SocketChannel sc ssc.accept();channels.add(sc);IteratorSocketChannel iterator channels.iterator();
while (iterator.hasNext()) {
SocketChannel channel iterator.next();ByteBuffer buffer ByteBuffer.allocate(10);//读取数据int len channel.read(buffer);ByteBufferUtil.debugAll(buffer);buffer.clear();log.debug(after read...{}, channel); }
}}
}
客户端
public class SocketChannelClient {public static void main(String[] args) throws IOException {SocketChannel sc SocketChannel.open();sc.connect(new InetSocketAddress(localhost, 8080));System.out.println(waiting...);}
} 非阻塞 非阻塞模式下相关的方法都不会让线程暂停 在ServerSocketChannel.accept()在没有建立连接时会返回null. SocketChannel.read在没有数据可读时返回0但线程不必阻塞可以执行其他SocketChannel的read或者ServerSocketChannel.accept 写数据的时候知识等待数据写入channel即可,无需等Channel通过网络把数据发出去。 非阻塞模式下即使没有连接建立和可读数据线程任然在不断运行拜拜浪费CPU 数据复制过程中线程实际还是阻塞的。(AIO改进的地方) 服务端代码
package com.aqiuo.socketchannel;
import com.aqiuo.buffer.ByteBufferUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
Slf4j
public class TestSocketChannel {public static void main(String[] args) throws IOException {//开启服务ServerSocketChannel ssc ServerSocketChannel.open();//绑定端口ssc.bind(new InetSocketAddress(8080));ssc.configureBlocking(false); //非阻塞模式//连接的集合ListSocketChannel channels new ArrayList();while (true) {//等待建立连接非阻塞线程还好继续向下运行没有连接返回nullSocketChannel sc ssc.accept();if(sc!null){log.info(connected...{},sc);sc.configureBlocking(false);//非阻塞模式channels.add(sc);}IteratorSocketChannel iterator channels.iterator();while (iterator.hasNext()) {
SocketChannel channel iterator.next();ByteBuffer buffer ByteBuffer.allocate(10);//非阻塞读取数据//接受客户端发送的数据。没有读到数据返回0int len channel.read(buffer);if(len0){buffer.flip();ByteBufferUtil.debugAll(buffer);buffer.clear();log.info(after read...{},channel);}
}
}}
} 多路复用
单线程可以搭配Selector完成对多个channel可读可写事件的监控称之为多路复用 多路复用仅仅针对网络IO,普通文件IO无法利用多路复用。 如果不用Selector的非阻塞模式线程大部分事件都在做无用功而Selector能够保证。 有连接事件时采去连接 有可读事件才去读取。 有可写事件才去写入。 限于网络传输能力Channel 未必时时可写一旦 Channel 可写会触发 Selector 的可写事件
Selector 创建
Selector selector Selector.open();
绑定 Channel 事件
也称之为注册事件绑定的事件 selector 才会关心
channel.configureBlocking(false);
SelectionKey key channel.register(selector, 绑定事件); channel 必须工作在非阻塞模式 FileChannel 没有非阻塞模式因此不能配合 selector 一起使用 绑定的事件类型可以有 connect - 客户端连接成功时触发 accept - 服务器端成功接受连接时触发 read - 数据可读入时触发有因为接收能力弱数据暂不能读入的情况 write - 数据可写出时触发有因为发送能力弱数据暂不能写出的情况
监听 Channel 事件
可以通过下面三种方法来监听是否有事件发生方法的返回值代表有多少 channel 发生了事件
方法1阻塞直到绑定事件发生
int count selector.select(); 方法2阻塞直到绑定事件发生或是超时时间单位为 ms
int count selector.select(long timeout);
方法3不会阻塞也就是不管有没有事件立刻返回自己根据返回值检查是否有事件
int count selector.selectNow(); select 何时不阻塞 事件发生时 客户端发起连接请求会触发 accept 事件 客户端发送数据过来客户端正常、异常关闭时都会触发 read 事件另外如果发送的数据大于 buffer 缓冲区会触发多次读取事件 channel 可写会触发 write 事件 在 linux 下 nio bug 发生时 调用 selector.wakeup() 调用 selector.close() selector 所在线程 interrupt