블록킹은 다른 작업이 완료될 때까지 현재 작업을 중단하는 방식입니다.
블록킹은 단순한 작업에 적합합니다. 예를 들어, 파일에서 데이터를 읽거나 쓰는 간단한 작업을 수행할 때 블록킹을 사용할 수 있습니다. 블록킹은 구현이 간단하고 이해하기 쉽다는 장점이 있습니다.
블록킹 예시)
다른 작업이 완료될 때까지 현재 작업을 중단하지 않는 방식입니다.
논블록킹은 고성능 작업에 적합합니다. 예를 들어, 네트워크에서 데이터를 전송하거나, 파일에서 대량의 데이터를 읽거나 쓰는 작업을 수행할 때 논블록킹을 사용할 수 있습니다. 논블록킹은 성능이 높지만, 구현이 복잡하고 이해하기 어려울 수 있습니다.
블록킹과 논블록킹은 동기(Synchronous)와 비동기(Asynchronous)와도 밀접한 관련이 있습니다. 동기는 작업이 완료될 때까지 기다리는 방식이고, 비동기는 작업이 완료될 때까지 기다리지 않는 방식입니다. 따라서 블록킹은 동기와 같은 의미로 사용되기도 합니다.
논블록킹 예시)
| 특징 | 블록킹 | 논블록킹 |
|---|---|---|
| 다른 작업 완료 여부에 따른 스레드 상태 | 동기 | 비동기 |
| 성능 | 저성능 | 고성능 |
| 복잡성 | 낮음 | 높음 |
| 사용예 | 단순 작업 | 고성능 작업 |
블록킹과 논블록킹은 동기(Synchronous)와 비동기(Asynchronous)와도 밀접한 관련이 있습니다. 동기는 작업이 완료될 때까지 기다리는 방식이고, 비동기는 작업이 완료될 때까지 기다리지 않는 방식입니다. 따라서 블록킹은 동기와 같은 의미로 사용되기도 합니다.
I/O는 Blocking I/O의 약자로, 입출력 작업이 완료될 때까지 해당 작업을 요청한 스레드를 차단합니다. 예를 들어, 파일에서 데이터를 읽는 작업을 수행한다고 가정해 보겠습니다. 이때 I/O를 사용하면 파일에서 데이터를 읽을 수 있을 때까지 해당 스레드는 대기 상태가 됩니다.
I/O 작업은 일반적으로 다음과 같은 단계로 수행됩니다.
자바에서는 InputStream과 OutputStream을 사용하여 I/O 작업을 수행할 수 있습니다.
FileInputStream fis = new FileInputStream("data.txt");
byte[] bytes = new byte[1024];
int read = fis.read(bytes); //blocking
이 코드에서는 read() 메서드가 데이터를 모두 읽을 때까지 스레드가 차단됩니다. 즉, read() 메서드가 데이터를 읽을 수 있을 때까지 스레드는 대기 상태가 됩니다.
예를 들어, 파일에서 데이터를 읽는 작업을 수행하는 경우 다음과 같은 단계로 수행됩니다.
이러한 방식으로 I/O 작업을 수행하면 작업이 완료될 때까지 스레드가 대기 상태가 됩니다. 따라서 I/O 작업이 자주 발생하는 경우 성능이 저하될 수 있습니다.
N/I/O는 이러한 문제를 해결하기 위해 도입된 방식입니다. N/I/O는 작업을 요청하는 스레드를 차단하지 않고 작업이 완료될 때까지 대기하는 별도의 스레드를 생성하는 방식으로 수행됩니다.
N/I/O는 Non-Blocking I/O의 약자로, 입출력 작업이 완료될 때까지 해당 작업을 요청한 스레드를 차단하지 않습니다. 예를 들어, 파일에서 데이터를 읽는 작업을 수행한다고 가정해 보겠습니다. 이때 N/I/O를 사용하면 파일에서 데이터를 읽을 수 있는 데이터가 있을 때까지 해당 스레드는 다른 작업을 수행할 수 있습니다.
아래는 N/I/O를 사용하여 파일에서 데이터를 읽는 코드입니다.
AsynchronousFileChannel afc = AsynchronousFileChannel.open(Paths.get("data.txt"));
afc.read(ByteBuffer.allocate(1024), null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
// 데이터를 읽은 후 처리할 작업
}
@Override
public void failed(Throwable exc, Void attachment) {
// 데이터 읽기 실패 시 처리할 작업
}
});
이 코드는 read() 메서드를 호출하여 파일에서 데이터를 읽습니다. read() 메서드는 CompletionHandler 객체를 인수로 받습니다. CompletionHandler 객체는 데이터 읽기가 완료되었을 때 또는 실패했을 때 호출됩니다.
이 코드에서는 read() 메서드가 데이터를 읽기 시작하면 스레드는 다른 작업을 수행할 수 있습니다. read() 메서드가 데이터를 모두 읽으면 CompletionHandler 객체의 completed() 메서드가 호출됩니다.
위 코드의 파일에서 데이터를 읽는 작업을 수행하는 경우 다음과 같은 단계로 수행됩니다.
이러한 방식으로 N/I/O 작업을 수행하면 작업이 완료될 때까지 스레드를 차단하지 않기 때문에 성능을 향상시킬 수 있습니다.
자바의 I/O와 N/I/O는 모두 입출력 작업을 수행할 때 사용됩니다. 그러나 I/O는 작업이 완료될 때까지 스레드를 차단하는 반면, N/I/O는 작업이 완료될 때까지 스레드를 차단하지 않는 차이점이 있습니다.
따라서 I/O는 단순한 입출력 작업을 수행할 때 사용되고, N/I/O는 고성능 입출력 작업을 수행할 때 사용됩니다.
I/O를 사용하는 작업의 예시)
N/I/O를 사용하는 작업의 예)
| 특징 | I/O | N/I/O |
|---|---|---|
| 입출력 작업 완료 여부에 따른 스레드 상태 | 차단 | 비차단 |
| 성능 | 저성능 | 고성능 |
| 복잡성 | 낮음 | 높음 |
| 사용예 | 단순 작업 | 고성능 작업 |
| 입출력 방식 | 스트림 | 채널(양방향 입출력 가능) |