BIO 和 NIO 做为 Server 端,当创建了 10 个链接时,分别产生多少个线程?服务器
答案: 由于传统的 IO 也就是 BIO 是同步线程堵塞的,因此每一个链接都要分配一个专用线程来处理请求,这样 10 个链接就会建立 10 个线程去处理。而 NIO 是一种同步非阻塞的 I/O 模型,它的核心技术是多路复用,可使用一个连接上的不一样通道来处理不一样的请求,因此即便有 10 个链接,对于 NIO 来讲,开启 1 个线程就够了。多线程
public
class
DemoServer
extends
Thread
{
private
ServerSocket serverSocket;
public
int getPort()
{
return serverSocket.getLocalPort();
}
public
void run()
{
try
{
serverSocket =
new
ServerSocket(0);
while
(true)
{
Socket socket = serverSocket.accept();
RequestHandler requestHandler =
new
RequestHandler(socket);
requestHandler.start();
}
}
catch
(IOException e)
{
e.printStackTrace();
}
finally
{
if
(serverSocket !=
null)
{
try
{
serverSocket.close();
}
catch
(IOException e)
{
e.printStackTrace();
}
}
}
}
public
static
void main(String[] args)
throws
IOException
{
DemoServer server =
new
DemoServer();
server.start();
try
(Socket client =
new
Socket(InetAddress.getLocalHost(), server.getPort()))
{
BufferedReader bufferedReader =
new
BufferedReader(new
InputStreamReader(client.getInputStream()));
bufferedReader.lines().forEach(s ->
System.out.println(s));
}
}
}
// 简化实现,不作读取,直接发送字符串
class
RequestHandler
extends
Thread
{
private
Socket socket;
RequestHandler(Socket socket)
{
this.socket = socket;
}
@Override
public
void run()
{
try
(PrintWriter out =
new
PrintWriter(socket.getOutputStream());)
{
out.println("Hello world!");
out.flush();
}
catch
(Exception e)
{
e.printStackTrace();
}
}
}
这样,一个简单的 Socket 服务器就被实现出来了。并发
(图片来源于杨晓峰)机器学习
public
class
NIOServer
extends
Thread
{
public
void run()
{
try
(Selector selector =
Selector.open();
ServerSocketChannel serverSocket =
ServerSocketChannel.open();)
{// 建立 Selector 和 Channel
serverSocket.bind(new
InetSocketAddress(InetAddress.getLocalHost(),
8888));
serverSocket.configureBlocking(false);
// 注册到 Selector,并说明关注点
serverSocket.register(selector,
SelectionKey.OP_ACCEPT);
while
(true)
{
selector.select();// 阻塞等待就绪的 Channel,这是关键点之一
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while
(iter.hasNext())
{
SelectionKey key = iter.next();
// 生产系统中通常会额外进行就绪状态检查
sayHelloWorld((ServerSocketChannel) key.channel());
iter.remove();
}
}
}
catch
(IOException e)
{
e.printStackTrace();
}
}
private
void sayHelloWorld(ServerSocketChannel server)
throws
IOException
{
try
(SocketChannel client = server.accept();)
{ client.write(Charset.defaultCharset().encode("Hello world!"));
}
}
// 省略了与前面相似的 main
}
能够看到,在前面两个样例中,IO 都是同步阻塞模式,因此须要多线程以实现多任务处理。而 NIO 则是利用了单线程轮询事件的机制,经过高效地定位就绪的 Channel,来决定作什么,仅仅 select 阶段是阻塞的,能够有效避免大量客户端链接时,频繁线程切换带来的问题,应用的扩展能力有了很是大的提升。下面这张图对这种实现思路进行了形象地说明。socket
做者: 王磊的博客分布式
免费Java资料领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高并发分布式、大数据、机器学习等技术。
传送门: https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q