一直在写业务代码,无非也就是增删改查,相对自己有个提升,就开始学习nio,并且打算记录下来
nio与传统的io有很大的区别,比如说非阻塞,但是具体体现在那里,本篇会介绍(如果有不足的地方请提出)
下面是一个使用传统io的socket的例子代码
public class OIoSocket {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(20020);
System.out.println("server start=======================");
while (true){
final Socket socket = serverSocket.accept();
System.out.println("accept client==================");
clientMsg(socket);
}
}
public static void clientMsg(Socket socket){
try{
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream();
while (true){
int read = inputStream.read(bytes);
if (read != -1){
System.out.println(new String(bytes,0,read));
}else {
break;
}
}
} catch (Exception e){
e.printStackTrace();
}finally {
try {
System.out.println("socket close==============");
socket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
代码很简单,我们来运行一下,并且打上断点
一步一步运行,可以看到,第一条打印是输出了,执行到accept的时候,就阻塞,下面的那个打印不会被执行
我们使用telnet来模拟个客户端
执行后发现,第二条输出执行了
这个时候,我们继续断点执行,发现在inputStream.read(bytes);这段代码时,断点停掉了,
所以可以做个总结,传统的socket有两个阻塞地方一个是server.accept();,另外一个是inputStream.read(bytes);,如果是inputStream.read(bytes);很容易就会看出,如果当前的没有执行完,又有一个新的socket进来,将在此阻塞,如下图,我又新创建了telnet,但是控制台没有任何反应,输出还是之前的
那么这就很尴尬了,如何避免呢,对代码进行如下的改造
public class OIoSocket {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
ServerSocket serverSocket = new ServerSocket(20020);
System.out.println("server start=======================");
while (true){
final Socket socket = serverSocket.accept();
System.out.println("accept client==================");
executorService.execute(new Runnable() {
@Override
public void run() {
clientMsg(socket);
}
});
}
}
public static void clientMsg(Socket socket){
try{
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream();
while (true){
int read = inputStream.read(bytes);
if (read != -1){
System.out.println(new String(bytes,0,read));
}else {
break;
}
}
} catch (Exception e){
e.printStackTrace();
}finally {
try {
System.out.println("socket close==============");
socket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
加入线程池,就会解决这个问题,做telnet不会出现上面的两个尴尬
但是如果用这种方式,会非常消耗性能,举个例子,线程池就像是餐厅,来一个客人,就得给他准备个服务员,我擦得要多少个服务员, 老板肯定赔钱 那么怎么办?