Java SE 8 의 새로운 기능.

2014/06/30 21:34

서비 JAVA

Java 8 의 closure, lambda, Nashorn 등 굵직한 변화에 묻혀 잘 화자되진 않지만 몇 가지 유용한 기능을 살펴보면
  1. Stamped Lock
    멀티 쓰레드 코드는 오랜 기간 (지금도 여전히) 서버 개발자의 골칫거리 중에 하나이다. 오랜 시간 Java Core에는 공유된 자원에 대해 최소한의 잠금시간을 위한 여러 라이브러리들이 추가되어 왔다. 대표적인 ReadWriteLock는 읽기와 쓰기를 위한 lock을 분리하여 잠금시간을  최소화할 수 있도록 지원( 동기화 클래스 - ReadWriteLock 인터페이스의 ReentrantReadWriteLock ) 하고 있다. 이게 이론상으로는 나이스한 아이디어 이긴한데 실제로 이 ReadWriteLock은 너무 느리다는 문제가 있다.
    이 문제를 해결하기 위해 Java 8에서는 StampedLock 이라는 새로운 ReadWrite lock을 소개하고 있다. 좋은 소식은 이 StampedLock은 정말 빠르다는거고 나쁜소식은 코드를 작성하는게 좀 더 복잡하다는거다. 이 lock은 reentrant 하지 않으며, 이는 곧 deadlocking에서 자유로움을 의미한다.
    [code java]StampedLock lock = new StampedLock();
    //빠른 non-blocking lock 획득
    long stamp = lock.tryOptimisticRead();   
    // 원하는 동작 작성.
    work();
    if (lock.validate(stamp)) {
    //work() 작업 성공. 다른 writer thread 와 경합 없었음.
    } else { // 다른 쓰레드의 write 작업으로 경합이 있다면 read lock으로 재시도.
    //스탬프를 변경하는동안 다른 스레드는 쓰기 잠금을 획득해야함.    
    //기존의 무거운 read lock으로 변경.
    //전통적인 blocking lock 획득
    stamp = lock.readLock(); 
    try {
    //다시 한번 시도
    work();
    } finally {
    //lock 해제
    lock.unlock(stamp);
    }
    }
    [/code]
    StampedLock과 기존의 ReadWriteLock , synchronized 과의 성능 비교 아티클도 있으니 참고.

  2. Concurrent Adder
    가장 기본적인 동시성 패턴은 읽기 / 쓰기에 대한 숫자 카운터이다. 이걸 처리하는데는 많은 방법이 있지만 Java 8에서 제공하는것 만큼 효율적이거나 우아하진 못했다. 지금까지는 sun.misc.Unsafe class를 활용한 CPU의 CAS( Compare and Swap ) 인스트럭션에 직접 counter를 설정하는 Atomics를 이용하는것이었다. 이 방식의 문제는 경합에의해 CAS에 실패하는 경우 AtomicInteger를 증가하면서 CAS에 성공할때까지 루프 상태가 되는데 이 부분이 성능의 발목을 잡고 있었다.
    Java8의 Concurrent Adder 계열의 클래스는 read / write에 함께 사용하는 편리한 방법을 제공한다. 엄청 간단해서 LongAdder 객체를 만들고 add() 나 intValue() 같은 메소드를 호출하기만 하면된다. 

    기존 Atomics와 Adder의 차이점은 경합에의한 CAS 실패 시 Adder는 CPU를 spin하는 대신 증분값(delta)를 해당 쓰레드를 위해 할당된 internal cell object에 기록한다. 그런 다음 intValue() 결과에 다른 보류중인 cell에 기록해둔 delta를 더한다. 이것으로 CAS를 시도하거나 다른 쓰레드를 block하는 횟수를 줄일 수 있게된다.

  3. Parallel Sorting
    conccurent Adder의 고속화에 힘입어 Java 8에서는 소팅을 고속화 할 수 있는 간결한 벙법을 제공한다. 사용방법도 상당히 단순하다.[code java]
    //기존방식
    Array.sort(arrayToSort);
    //새로운 방식
    Array.parallelSort(arrayToSort);
    [/code]

  4. new Date API
    Java 8 에서는 완전히 새로운 date-time API를 제공한다. 사용하기 편하고 정확도가 높은 joda time API가 Java core library에 포함 되었다.지금까지의 Date 관련 API는 대부분 deprecated 된다. 새로운 API는 기능적이면서도 우아하지만 아쉽게도 기존 api를 사용하는 방대한 코드는 여전히 남아있고 빠른시간에 새로운 api로 교체되지는 못할것이다.

    기존 api (java.util.Date java.sql.Date 등)와 신규 api의 갭을 메우기위해 기존 Date 객체를 Instant로 변경하기 위한 toInstant() 메소드와 ㅑInstant를 Date 로 변경하기 위한 from(Instant instant) static 메소드를 추가하였다. 이는 특히 새로운 API보다는 기존 API로 작업하는것을 선호하는 개발자에게 효과적일 수 있다.

  5. OS Process Control
    JNI를 통한 OS 프로세스 호출이 필요악일 지라도 자바 코드 내에서 OS 프로세스를 실행한 경우 실행중인 프로세스를 제어하기 어려웠다. 이를 개선하기위해 Process class에 다음 세개의 메소드를 추가하였다.
    - destroyFprcibly() : 기존 destroy() 보다 더 높은 프로세스 종료율을 제공.
    - isAlive() : java code를 통해 실행한 프로세스가 살아있는지 확인.
    - waitFor() : 새로 오버로드한 waitFor() 메소드를 통해 프로세스 종료를 얼마나  기다릴지 정할수 있음.

    프로세스가 끝나지 않은 경우 끝내고 다음 코드로 진행.
    [code java] if (process.wait(MY_TIMEOUT, TimeUnit.MILLISECONDS)){
    //success!
    } else {
    process.destroyForcibly();
    } [/code]
    코드가 완료되기 전 어떤 프로세스도 남겨두지 않으려 할 경우, 느리지만 확실하게 OS에서 사라지게하기.
    [code java] for (Process p : processes) { if (p.isAlive()) { p.destroyForcibly(); } } [/code]

  6. Overflow 대응 숫자 연산
    숫자 연산에서의 overflow는 가끔 끔찍한 버그를 만든다. 특히 int 값을 증가하는 count 값을 이용하는 시스템에서 특히 그런데, 개발계나 스테이징에서는 발견하지 못하고 오랜기간 운영하는 production 모드에서 발생하면 그야말로 재앙이다.

    이런 상황에 도움이 되고자 Java 8에는 부호에 민감한 계산에서 overflow발생 시 ArithmeticException을 던지는 새로운 exact 메소드가 추가되었다.
    [code java]
    //overflow 시 ArithmeticException 발생
    int multi = Math.multiplyExact( bigA, bigB ); [/code]
    이 새로운 메소드의 한가지 단점이라면 overflow가 발생할 코드의 위치를 찾는것은 개발자의 몫이란거다.

  7. Secure Random Generator
    Java는 근 몇년 간 보안 허점과 분투하고 있다. JVM과 Framework에 걸친 광범위한 보안조치가 취해지고 있다.  낮은 수준의 난수로 암호화 키를 생성하거나, 민감한 정보를 해시하는 경우도 해킹에 취약한 시스템을 만든다.

    오랜기간동안 Random Number Generator algorithm은 개발자 영역으로 남겨져 있었고. 구현체가 특정 하드웨어 / OS / JVM에 의존하는 경우, 원하는 알고리즘을 사용하지 못할 수 있었다. 문제는 이런 경우 응용 프로그램은 공격의 더 취약한 Generator를 기본값으로하는 경향이 있었다.

    Java 8에는 JVM 보안 공급자/알고리듬을 선택하기를 원하는 개발자를 위해 SecureRandom.getInstanceStrong() 를 새로이 추가하였다. 이 메소드는 hardware / OS / JVM에 대한 완전한 통제권이 없는 상황에서 ( cloud , PaaS 등.. ) 개발 할 때 적절한 솔루션이 될 수 있다.

  8. Optional 참조
    NullPointer는 말하자면 문지방에 찧은 발가락 같다. 실제로 저명한 언어 디자이너 / 석학 중 일부는 null reference를 고안한 건 엄청남 실수라고 말하는 사람도 있다. 나는 개인적으로 null reference 가 있는게 더 자연스럽다고 생각하는 쪽이긴 하지만... 여하튼 null pointer 관련 에러는 성가신 존재임에는 틀림없다. Java 8 에서는 이런 Null pointer 처리를 도와줄 Optional<T> 템플릿이 도입되었다.

    Scala와 Haskell에서 빌려온 이 템플릿은, 템플릿에 전달하거나 함수에의해 반환 된 참조가 null이 될 수있는 경우를 명시적으로 언급하는 것이 가능해졌다. 이렇게 함으로써 코드 작성 시 document 도움 없이도 런타임에 특정 참조가 null인 경우가 있을지 없을지 guess game 하는 정력 낭비를 줄여준다.
    [code java]Optional<User> tryFindUser(int userID) { }
    //혹은
    void processUser(User user, Optional<Cart> shoppingCart) { }
    [/code]또한, Optional 템플릿은 null 이외의 값을 사용할 수 있는지 확인하기 위해, isPresent() 람다에서는 ifPresent() 메소드를 제공한다.
2014/06/30 21:34 2014/06/30 21:34
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다