在调用程序的时候会出现两种情况,一种是阻塞,另一种是非阻塞。当我们需要某种调用产生结果后执行时,会选择阻塞对程序暂时挂起。而非阻塞的操作是把立刻返回,而不是对线程进行阻止。下面就java中阻塞和非阻塞的概念带来讲解,然后就代码的使用上为大家进行说明。
1.概念
阻塞就是指在调用结果返回之前,当前线程会被挂起,一直处于等待消息通知的状态,不能执行其他业务。只有当调用结果返回之后才能进行其他操作。
非阻塞与阻塞的概念相对应,就是指不能立即得到结果之前,该函数不会阻塞当前线程,而是会立即返回。
2.阻塞式IO
一个新的连接,我们就新开一个线程来处理这个连接,之后的操作全部由那个线程来完成。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLEN 4096 int main(int argc, char** argv) { int listenfd, sock_fd; struct sockaddr_in servaddr; char buff[MAXLEN]; int n; if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ printf("create socket error: %s(errno: %d)/n",strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(8001); if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } if( listen(listenfd, 10) == -1){ printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("waiting for client to connect\n"); while(1){ if( (sock_fd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){ printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } n = recv(sock_fd, buff, MAXLEN, 0); buff[n] = '\0'; printf("recv msg from client: %s\n", buff); close(sock_fd); break; } close(listenfd); }
3.非阻塞式IO
非阻塞 IO 的核心在于使用一个 Selector 来管理多个通道,可以是 SocketChannel,也可以是 ServerSocketChannel,将各个通道注册到 Selector 上,指定监听的事件。
public class SelectorServer { public static void main(String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel server = ServerSocketChannel.open(); server.socket().bind(new InetSocketAddress(8080)); // 将其注册到 Selector 中,监听 OP_ACCEPT 事件 server.configureBlocking(false); server.register(selector, SelectionKey.OP_ACCEPT); while (true) { int readyChannels = selector.select(); if (readyChannels == 0) { continue; } Set<SelectionKey> readyKeys = selector.selectedKeys(); // 遍历 Iterator<SelectionKey> iterator = readyKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()) { // 有已经接受的新的到服务端的连接 SocketChannel socketChannel = server.accept(); // 有新的连接并不代表这个通道就有数据, // 这里将这个新的 SocketChannel 注册到 Selector,监听 OP_READ 事件,等待数据 socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 有数据可读 // 上面一个 if 分支中注册了监听 OP_READ 事件的 SocketChannel SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int num = socketChannel.read(readBuffer); if (num > 0) { // 处理进来的数据... System.out.println("收到数据:" + new String(readBuffer.array()).trim()); ByteBuffer buffer = ByteBuffer.wrap("返回给客户端的数据...".getBytes()); socketChannel.write(buffer); } else if (num == -1) { // -1 代表连接已经关闭 socketChannel.close(); } } } } } }
以上就是Java阻塞和非阻塞的使用方法,相信大家已经对程序调用时的两种不同执行方法有所了解,根据我们所想要要达到的结果,分别选择阻塞和非阻塞的操作。