2013년 10월 3일 목요일

자바7 NIO.2 - 내용정리 9장 (비동기 채널 API)

chapter 9. 비동기 채널 API
기본 인터페이스는 java.nio.channels.AsynchronousChannel 임.
주요 하위 클래스
  1. AsynchronousFileChannel
  2. AsynchronousServerSocketChannel
  3. AsynchronousSocketChannel
  4. AsynchronousDatagramChannel (최종 버젼에서 제거됨 - 베타 까지 존재함.)
비동기 채널 그룹 - AsynchronousChannelGroup 클래스

9.1 동기 I/O와 비동기 I/O의 비교

목적
동기 I/O - 간단하게 요청을 하나 보내고 응답을 하나 받고 싶을 때 , 연결당 스레드 하나, 성능, 확장성이 제한됨
비동기 I/O - 성능과 확장성 좋음. 매우 많이 시간이 걸리는 I/O는 비동기로 최적화 할 수 있다.
** 즉 매우 긴 시간 걸리는 동작은 비동기 , 짧은 시간 걸리는 동작은 동기로 하면 좋음.

9.2 비동기 I/O의 큰 그림

자바에서 비동기I/O은 비동기 채널을 말함.
모든 비동기 I/O은 시작하고 완료되었을 때 통지를 받는다. -> 중요한 규칙
비동기 I/O의 형식
  1. 미처리 결과(Pending result)
  2. 완료 결과(Complete result)
9.2.1 미처리 결과와 Future 클래스
java.util.concurrent.Future<V> 객체는 비동기I/O 작업의 미처리 결과를 나타냄. Future의 메소드를 통해서 작업 결과(완료,대기중)을 알수 있다.
Future 메소드
  • isDone() : 작업 완료 여부
  • isCancelled() : 작업 취소 여부
  • cancel() : 명시적으로 작업 취소 하기 (성공하면 true를 반환)
  • get() , get(long,TimeUnit) : 결과가 준비될 때까지 혹은 주어진 시간 만큼 대기
    타입 아웃되면 TimeoutException이 발생한다.
비동기 I/O 작업을 취소 특징
  • 대기중에 모든 쓰레드 CancellationException을 발생한다.
  • 올바르게 취소된다는 보장은 할 수 없음. 최소한 I/O 작업이 시작하는 것은 막을 수있음.
  • cancel(true)를 사용하면 채널을 닫아서 I/O 작업이 중단 될 수 있음.
  • 이 채널의 외부 I/O는 AsychronousCloseException이 발생
  • 취소된 읽기/쓰기 작업과 관련된 I/O 버퍼는 채널이 열려 있어도 더 이상 접근하지 못하게 됨.
9.2.2 완료 결과와 CompletionHandler 인터페이스
콜백 매커니즘 방법, 비동기 작업에 콜백을 등록해두고 작업이 완료되거나 실패하면 핸들러(CompletionHanndler) 호출한다.
완료 핸들러 형식은 CompletionHanndler<V,A> 이면 V - 반환값 , A - I/O 작업에 첨부된 객체의 타입. A를 통해서 어느 작업이 완료 되었는지 알 수 있다. ** 쓰레드가 유지되는 것을 피하기 위해서 빠른 시간에 완료해야 함.
CompletionHanndler의 주요 메소드
  • completed() : 완료되었을 때 호출됨.
  • failed() : 작업이 실패 했을 때 호출됨.
9.2.3 비동기 채널의 유형 (3가지)
  1. AsynchronousFileChannel : 파일 읽기,쓰기, 조작을 위한 비동기 채널
  2. AsynchronousServerSocketChannel : 서버(TCP) 소켓 위한 비동기 채널
  3. AsynchronousSocketChannel : 클라이언트 소켓 위한 비동기 채널
AsynchronousFileChannel 채널 작업 시 발생하는 예외들
  • AsynchronousCloseException - close() 메소드를 사용하여 닫을 때 발생함.
  • ClosedChannelException - close() 메소드를 사용하여 닫은 후 다른 작업 하려고 하면 발생함.
  • NonReadableChannelException - 읽기 준비가 되어 있지 않을 때 읽기 시도 할때
  • NonWritableChannelExcepiton - 쓰기 준비가 되어 있지 않을 때 쓰기 시도 할때
  • OverlappingFileLockException - 자바 가상머신에 의해서 잠금이 되어 있는데 잠금을 시도할 때
AsynchronousServerSocketChannel 채널 작업 시 발생하는 예외들
  • AsynchronousCloseException - close() 메소드를 사용하여 소켓 채널을 닫을 때 발생함.
  • ClosedChannelException - close() 메소드를 사용하여 닫은 후 다른 작업 하려고 하면 발생함.
  • ShutdownChannelGroupException - 채널 그룹이 닫혀 있는데 열기를 시도 할때
  • NotYetBoundException - 바인딩되지 않은 채널에 대해서 accept() 메소드를 호출할 때
  • AcceptPendingException - 이전의 수락 처리가 완료되기 전에 어떤 쓰레드가 수락 처리를 시작하려 할때.
AsynchronousSocketChannel 채널 작업 시 발생하는 예외들 및 주의 사항
  • AsynchronousCloseException - close() 메소드를 사용하여 소켓 채널을 닫을 때 발생함.
  • ClosedChannelException - close() 메소드를 사용하여 닫은 후 다른 작업 하려고 하면 발생함.
  • NotYetConnectedException - 연결되지 않은 채널에 대해 I/O 연산을 호출할 때
  • ReadPendingException - 이전의 읽기 처리가 완료되기 전에 어떤 쓰레드가 읽기 처리를 시작하려 할 때
  • WritePendingException - 이전의 쓰기 처리가 완료되기 전에 어떤 쓰레드가 쓰기 처리를 시작하려 할 때
  • AlreadyConnectedException - 채널이 이미 연결돼 있는데 연결하려 할 때
  • ConnectionPendingException - 이 채널에 대해 연결 작업이 이미 진행 중인데 채널에 연결하려 할 때
  • AsynchoronousSocketChannel에서 read(),write() 메소드는 읽기,쓰기 처리를 시작할 때 타임 아웃을 지정할 수 있다. 작업이 완료되기 전에 타임아웃이 경과하면 InterruptedByTimeoutException 예외가 작업을 완료한다. 일관되지 않은 상태에서 타임 아웃은 채널을 무시 할 수도 있다. 구현에서 바이트를 채널에 기록하는 것이나 읽어오는 것을 보증하지 않는다면 구현체는 채널을 구현체 한정 에러 상태로 둘 수 있다. 이 상태에서 읽기나 쓰기 처리를 시작하려 하면 지정되지 않은 런타임 예외가 발생한다.
9.2.4 그룹
AsynchronousChannelGroup 클래스 - 비동기 채널 그룹 개념을 위한, 채널의 위한 모든 스레드가 공유하는 리소스와 스레드 풀을 캡슐화 함. 채널을 실제 적으로 그룹이 소유하고 있고 채널을 닫으면 그룹도 닫힌다.
기본 그룹
  • 개발자가 생성하는 그룹 외에 JVM에서도 자동으로 생선된, 시스템 전체에 적용되는 기본 그룹
  • 간단한 애플리케이션 유용
  • 그룹을 지정하지 않거나 null을 전달하면 기본그룹에 속한다.
  • 기본 그룹과 관련 시스템 속성(System.getProperty)
  • 첫번째 속성 - “java.nio.channels.DefaultThreadPool.threadFactory”,이 속성은 팩토리 객체를 생성할 때 사용하는 풀 클래스 이름이 들어 있으면 이 이름 생성된 객체의 newThread() 메소드를 사용해서 각 쓰레드 생성할 때 사용한다.
  • 두번째 속성 - “java.nio.channels.DefaultThreadPool.initialSize : 쓰레드 풀의 초기 크기(숫자형이어야 한다.)
사용자 지정 그룹
자신 용도에 맞는 그룹을 생성할 수 있다. AsychronousChannelGroup에서 제공하는 세 가지 메소드를 사용함.
  • 고정 스레드 풀 - public static AsynchronousChannelGroup withFixedThreadPool(int nThreads, ThreadFactory threadFactory) throws IOException
  • 캐시 스레드 풀 - public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor, int initialSize) throws IOException
    • 내부적으로 히든 쓰레드 풀을 사용해서 작업 한다.
    • OutOfMemory가 발생할 수 있다.(발생 조건은 모든 쓰레드가 잠기고 큐에 계속해서 쌓일 때) - 그러므로 모니터링을 해야 한다.
  • 지명 스레드 풀 - public static AsynchronousChannelGroup withThreadPool(ExecutorService executor) throws IOException
    • ExecutorService 사용하는 방식 , ExecutorServie 설정 할 때 주의 해야 함. 즉
    • 주의 사항 하나. 실행할 작업의 언바운딩 큐잉이나 다이렉트 핸드오프를 지원해야 한다.-> 무슨 소리인겨 그냥 번역 한것.
    • 주의 사항 둘. 작업(task)을 직접 호출하기 위해 쓰레드가 execute() 메소드를 호출하는 것을 허용해서는 안된다. -> 이해 가면 천재
그룹 종료 메소드 :
  • shutdown() , shutdownNow() 메소드를 사용. 만약 채널을 생성하려 하면 ShutdownChannelGroupException 예외가 발생한다.
    • shutdown() - 실행 중인 스레드를 강제로 중지하거나 인터럽트 하지 않는다.
    • shutdownNow() - 그룹을 강제 종료 한다.
  • awaitTermination() : 메소드에 타임아웃을 지정해서 호출하면 그룹이 종료될 때 까지 블록할 수있다.
  • isTerminated() : 그룹이 종료됐는지 확인 가능
  • isShutdown() : 종료됐는지 확인 가능

** ByteBuffer는 쓰레드 안정서이 없다. 작업중인 바이트 버퍼에 접근하지 않게 해야 한다. 이 문제해결 하기 위해서 ByteBuffer 풀을 사용한는 것이다. 메모리 관련 문제도 해결 가능함.

9.2.5 ExecutorService API 소개
관련 공식 문서 , 자바의 동시성과 멀티스레딩 개념에서 중요한 구성요소, 매우 방대하고 복잡한 API 임. 관련강좌 라스보겔
간단하게 설명하면 사용자 지정 스레트 풀을 만들 수 있는 편리한 방법을 제공함.
일반적으로 결과를 반환하지 않는 Runnable사용하지만 만약 결과를 받고 싶다면 java.util.concurrent.Callable를 사용할 수 있다.-> 결과는 Callable.call() 메서드의 내부에서 계산(재정의 할 수 있음). submit() 제출, 미처리 결과는 Future를 반환한다.

유용한 팁 - 만약 제품용으로 개선 하려면

  • 바이프 버퍼 풀을 사용하고 읽기 작업을 조절하라 -
  • 짧은 읽기 작업에만 블로킹을 사용하라
  • FIFO 큐를 사용하고, 쓰기 작업에 블로킹을 허용하라

댓글 없음: