목록전체 글 (115)
도당탕탕
thread safety level를 명시할 것 Immutable 인스턴스가 변하지 않는 경우, 예를 들어 String,Long,BigInteger 아무런 동기화과정이 필요 없음. Unconditionally thread-safe 인스턴스는 mutable이지만 외부적 동기화 없이 병렬로 사용될 수 있는 경우 예를 들어 AtomicLong, ConcurrentHashMap Conditionally thread-safe 몇몇 함수에만 외부적 동기화가 필요한 경우 예를 들어 Collections.synchronized wrapper에 의해 리턴되는 컬렉션 정확히 어떤 함수가 외부적 동기화를 필요로 하는지 명시해야 됨. Not thread-safe 인스턴스가 mutable이며, 모든 함수에서 외부적 동기화가 필..
동시성 컬렉션은 List, Queue, Map과 같은 표준 컬렉션 인터페이스에 동시성을 고려하여 구현한 고성능 컬렉션이다. 높은 동시성에 도달하기 위해 동기화를 각자의 내부에서 수행하는데 컬렉션에서 동시성을 무력화하는 건 불가능하며, 외부에서 락을 추가로 사용하면 오히려 속도가 느려진다. 따라서 동시성 컬렉션의 동시성을 무력화하지 못하기 때문에 여러 메서드를 원자적으로 묶어 호출하는 것도 못한다. 그래서 여러 동작을 하나의 원자적 동작으로 묶는 상태 의존적 메서드가 추가되었다. 예를 들면 다음과 같다. putIfAbsent을 사용한 intern 메서드 private static final ConcurrentMap map = new ConcurrentHashMap(); public static String..
Executor Framework java.util.concurrent 패키지에 존재 기존의 Thread 클래스보다 더 편리한 사용성 제공 객체생성 -> ExecutorService exec = Executors.newSingleThreadExecutor(); 실행 -> exec.execute(runnable); 종료 -> exec.shutdown(); Thread pool 작업의 모든 면을 설정하고 싶다면, Executors.ThreadPoolExecutor 사용 작은 프로그램(local에서 동작하는 프로그램)에 대해서는 Executors.newCachedThreadPool 사용 큰 프로그램(production용)에 대해서는 Executors.newFixedThreadPool 사용 작업의 단위를 tas..
동기화를 과도하게 사용할 경우 성능을 떨어뜨리고, 교착상태에 빠뜨리고, 심지어 예측할 수 없는 동작을 낳기도 한다. 즉 응답 불가와 안전 실패를 피하려면 동기화 메서드나 동기화 블록 안에서는 제어를 절대로 클라이언트에 양도하면 안 된다. 예를 들면 다음과 같다. 동기화된 영역 안에서는 재정의할 수 있는 메소드는 호출하면 안 된다. 클라이언트가 넘겨준 함수 객체를 호출해서도 안된다. 위와 같은 것들을 동기화된 영역에서는 바깥세상에서 온 외계인 메서드라 부른다. 외계인 메서드가 하는 일에 따라 동기화된 영역은 예외를 일으키거나, 교착상태에 빠지거나, 데이터를 훼손할 수도 있다. 구체적인 예를 한번 보자. 잘못된 코드, 동기화 블록 안에서 외계인 메서드를 호출한 경우 public class Observable..
Synchronization이 보장하는 것 함수에서 consistent 상태의 객체 읽기 스레드들이 서로가 변경한 사항들을 읽기 동기화 방법 1. synchronized 사용 public class StopThread { private static boolean stopRequested; public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread(() -> { int i = 0; while (!stopRequested) i++; }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; } } ..
너무 뻔하지만 프로그래머가 잘 어기는 것들 중 하나가 예외를 무시한다는 것이다. API 설계자가 메소드 선언에 예외를 명시하는 까닭은, 그 메소드를 사용할 때 적절한 조치를 취해달라고 말하는 것이다. 예외를 무시하기란 아주 쉽다. try문을 감싸고 catch 블럭에 아무것도 안하면 된다. 하지만 이는 다음과 같은 행위를 무시하는 것이다. 예외는 문제 상황에 잘 대처하기 위해 존재하는데 catch블록을 비워두면 예외가 존재할 이유가 없어진다. 물론 예외를 무시해야 할 때도 있다. 예를 들어 FileInputStream을 닫을 때가 그렇다. 파일의 상태를 변경하지 않았으니 복구할 것이 없으며, 필요한 정보는 이미 다 읽었다는 뜻이니 남은 작업을 중단할 이유도 없을 때 발생한 예외가 그렇다. 따라서 이러한 에..
실패원자성 실행도중 실패한 함수가 실패하더라도, 원본 객체는 변함없는 성질 실패원자성 보장 방법 immutable 객체 생성 함수 실행 전 파라미터를 체크 public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; } 실패할만한 로직을 함수의 앞부분에 배치 원본객체를 임시 객체로 복사한뒤, 작업이 성공하면 원본객체를 대체 함수 실행도중 발생한 실패를 캐치하여 원래 상태로 롤백 단, 멀티스레딩 환경에서 적절한 동기화 없이 객체를 변경한 경우, 불가능 정리 실..
자바에서 stack trace는 예외 객체의 toString 메서드를 호출해 출력한다. 보통 예외의 클래스 이름 뒤에 상세 메시지가 붙는 형태로 나타낸다. 이 정보를 통해 프로그래머 혹은 사이트 신뢰성 엔지니어가 실패 원인을 찾고 분석해 해결한다. 따라서 예외의 toString 메소드에 실패 원인에 관한 정보를 가능한 한 많이 담아 반환하는 일은 아주 중요하다. 그렇기 때문에 실패 순간을 포착하려면 발생한 예외에 관여된 모든 매개변수와 필드의 값을 실패 메시지에 담아야 한다. 예를 들면 IndexOutOfBoundException의 상세 메시지는 범위의 최솟값, 최댓값, 그리고 그 범위를 벗어났다는 인덱스의 값을 담아야 한다. 이 정보는 다음과 같이 실패에 관한 많은 것을 알려준다. 인덱스가 최솟값보다 ..