同步与异步
同步异步关注的是消息通信机制。同步,就是在发出一个调用时,没有得到结果之前,该调用就不返回。就是由调用者主动等待这个调用的结果。
异步相反,调用在发出后就返回了,没有返回结果。也就是说,一个异步过程调用后,调用者不会立刻得到结果。而是在调用后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
阻塞与非阻塞
关注的是程序在等待调用结果(消息,返回值)时的状态
阻塞调用是指调用结果返回之前,当前线程挂起。调用线程只有在结果返回之后才会返回。
非阻塞调用指在不能立刻得到结果时,该调用不会阻塞当前线程。
BIO BlockingIO
同步阻塞IO,数据的读取写入必须阻塞在一个线程内等待其完成。
活动链接数不高的情况下,可以让每个连接专注自己的IO且编程模型简单。当面对大量IO连接时,就无能为力。
并发量高,来一个客户端连接就开启一个线程;同时阻塞方法多,很多线程都在等待,CPU在线程之间反复切换,因此效率低。
package com.cloud.bio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1",8888));//开启一个插座,指定端口和地址(里面有很多插口供客户端连接)
while(true){
Socket s = ss.accept(); //阻塞方法,等在此处等待有客户端接入ss,如果没有线程就进入wait,直到客户端接入才被唤醒
new Thread(()->{
//一旦有客户端接入,开启一个新线程处理,主线程继续等待
handle(s);
}).start();
}
}
public static void handle(Socket s){
try{
byte[] bytes = new byte[1024];
int len = s.getInputStream().read(bytes);// 此处的read方法也是阻塞方法,如果客户端没发来消息,就会一直wait
System.out.println(new String (bytes,0,len));
s.getOutputStream().write(bytes,0,len); //write也是阻塞方法,如果客户端不接收,就阻塞在此处
s.getOutputStream().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.cloud.bio;
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket s = new Socket("127.0.0.1",8888); //连接服务器
s.getOutputStream().write("helloServer".getBytes()); //s是客户端这边看到的channel
s.getOutputStream().flush();
System.out.println("write over, waiting for msg back..");
byte[] bytes = new byte[1024];
int len = s.getInputStream().read(bytes);
System.out.println(new String(bytes,0,len));
s.close();
}
}
NIO New/Non-Blocking
单线程:Server 端有一个Selector选择器只专注客户端的连接,读取,和写入,(会盯在Server端的插座旁边,如果有客户连接,就接收进来建立连接,如果有客户写入,就读取进来。即发现一件事就处理一件事)
package com.cloud.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;