以服务器为例,在传统BIO模型下的服务器,每当一个新的请求到来的时候回分配一个线程去处理该请求,并且该线程在执行IO操作的时候会一直阻塞,知道IO操作完成或抛出异常才会返回。当网络情况不佳时,网络IO可能会耗费大量时间,那么就会同时有大量线程在服务器上阻塞着,很容易造成内存溢出。
这种模型被称为同步阻塞模型,同步指的是只有等待线程IO操作完成该线程才会返回,阻塞指的是IO没有完成的时候一直等待。
Server类,监听8080端口,在while循环里Server端阻塞在server.accept上,即等待请求传到8080端口上,从accept方法返回。后续new Thread是新建一个线程去处理请求。
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080;
ServerSocket server = null;
try {
server = new ServerSocket(port);
System.out.println("The server start in port "+port);
Socket socket = null;
while (true){
socket = server.accept();
Thread thread = new Thread(new TimeServerHandler(socket));
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (server!=null){
System.out.println("Time server close");
server.close();
server=null;
}
}
}
}
执行代码用jstack打印线程状态,看到server线程在17行“停止”,即阻塞在17行等待请求传过来。这种阻塞就是BIO里的B,block,一个IO没有完成就一直卡在那里。
有新的客户端接入新建线程执行处理方法,通过检查传过来的字符串是否是要求的“QUERY TIME ORDER”,如果是就返回当前服务器的时间,否则返回错误信息。
public class TimeServerHandler implements Runnable { private Socket socket; public TimeServerHandler(Socket socket) { this.socket = socket; } public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(),true); String currentTime = null; String body = null; while (true){ body = in.readLine(); if (body == null){ break; } System.out.println("The time server receive order: "+body); currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new Date(System.currentTimeMillis()).toString():"BAD ORDER"; out.println(currentTime); } } catch (IOException e) { e.printStackTrace(); if (in!=null){ try { in.close(); } catch (IOException ex) { ex.printStackTrace(); } } if (out!=null){ out.close(); out = null; } if (socket!=null){ try { socket.close(); } catch (IOException ex) { ex.printStackTrace(); }finally { socket=null; } } } } }
同时开启服务端和客户端后可以在控制台看到输出。
用线程池代替不停的新建线程,好处是线程池是有界的,避免在极端情况下不停新建线程。
public class TimeServer_ThreadPool { public static void main(String[] args) { int port = 8080; ServerSocket server = null; try { server = new ServerSocket(port); System.out.println("server start at port "+ port); Socket socket = null; ExecutorService pool = Executors.newFixedThreadPool(10); while (true){ socket = server.accept(); pool.execute(new TimeServerHandler(socket)); } } catch (IOException e) { e.printStackTrace(); } } }
NIO与BIO的区别在两点
原文:https://www.cnblogs.com/AshOfTime/p/10806165.html