阻塞IO对线程资源分配与使用的影响
- 线程资源占用:当线程执行阻塞IO操作时,该线程会被挂起,等待IO操作完成。在此期间,线程无法执行其他任务,但依然占用着系统分配给它的资源,如栈空间等。这意味着在阻塞期间,线程不能被调度去执行其他代码逻辑,造成了线程资源的浪费。
- 线程调度:操作系统的线程调度器会将CPU时间分配给其他可运行的线程。阻塞IO操作使得当前线程从运行状态变为阻塞状态,让出CPU,直到IO操作完成,线程才会重新变为可运行状态,等待调度器再次分配CPU时间。
常见阻塞IO场景及对线程状态的改变
- 文件读取:
- 场景:使用
FileInputStream
读取文件内容时,如下代码:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileReadExample {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("example.txt")) {
byte[] buffer = new byte[1024];
int bytesRead = inputStream.read(buffer);
while (bytesRead != -1) {
// 处理读取到的字节
bytesRead = inputStream.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 线程状态改变:当执行
inputStream.read(buffer)
时,如果文件内容还未准备好(例如文件正在从磁盘中读取到内存),线程会从运行状态变为阻塞状态。一旦数据可读,线程会从阻塞状态变为可运行状态,执行后续的读取和处理逻辑。
- 网络Socket读取:
- 场景:使用
Socket
进行网络通信,接收数据时,如下代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketReadExample {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8080)) {
try (Socket clientSocket = serverSocket.accept()) {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Received: " + inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 线程状态改变:当执行
in.readLine()
时,如果没有数据到达网络缓冲区,线程会从运行状态变为阻塞状态。当数据到达,线程会从阻塞状态变为可运行状态,读取并处理接收到的数据。