본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[Effective Java] 스레드 스케쥴러에 의존하지 말자

by 돼지왕 왕돼지 2017. 3. 17.
반응형

 [Effective Java] 스레드 스케쥴러에 의존하지 말자


api 문서, busy wait, CPU, Effective JAVA, executor framework, jvm, liveness, priority, Runnable, thread scheduler, thread.sleep, thread.sleep(0), thread.sleep(10, thread.yield, yield, [Effective Java] 스레드 스케쥴러에 의존하지 말자, 감소, 강렬, 결정, 공유 객체, 공정, 근본적인 원인, 독립적으로 유지, 변덕, 변동, 부담, 부하, 분주 대기, 성능, 성능 저해, 성능 향상, 스레드, 스레드 개수, 스레드 개수 줄이는 방법, 스레드 스케줄러, 스레드 스케쥴러, 스레드 우선 순위, 스레드 풀, 스케줄러, 앱 재구성, 운영체제, 유용한 일의 양, 음답성, 의존, 이식성, 자바 플랫폼, 작업, 작업의 크기, 정책, 정확성, 제어, 터무니, 평균 스레드 개수, 프로세서의 개수, 필요, 호출자, 활동성


-
많은 스레드가 runnable 상태일 때는 어떤 스레드를 실행시킬 것인지, 그리고 얼마 동안 실행시킬 것인지를 스레드 스케쥴러가 결정한다.
운영체제에서는 공정하게 그런 결정을 내리려고 하겠지만, 그 정책은 서로 다를 수 있다.
따라서 잘 작성한 프로그램은 그런 정책의 상세한 내용에 매달려서는 안 된다.
정확성이나 성능을 스레드 스케줄러에 의존하는 프로그램이라면 그 어떤 것도 이식성이 없어질 가능성이 크다.


-
강력하고, 응답성이 좋고, 이식성이 있는 프로그램을 작성하는 가장 좋은 방법은, runnable 상태의 평균 스레드 개수가 프로세서의 개수보다 그리 크지 않게 하는 것이다.
이렇게 하면 스레드 스케줄러는 선택의 여지 없이 runnable 상태의 스레드들을 그냥 실행시킬 것이다.


-
runnable 상태의 스레드 개수를 줄이는 주된 방법은,
스레드가 유용한 일을 하고 있지 않다면 실행하지 않도록 해야 한다.
Executor Framework 관점으로 본다면, 이것을 스레드 풀을 적합하게 만드는 것을 의미하며,
스레드가 수행하는 작업이 가급적 작으면서 서로 간에 독립적으로 유지되게 하는 것을 의미한다.
그렇다고 작업이 너무 작아도 안 된다.
너무 작으면 신속한 처리에 따른 부담이 성능을 저해할 것이기 때문이다.


-
공유되는 객체에 변동 사항이 없는지 반복적으로 확인하면서 기다리는 분주-대기(busy-wait) 상태에 스레드가 빠지면 안 된다.
프로그램이 스레드 스케줄러의 변덕스러움에 영향을 받게 되고, 또한 프로세서의 부하를 현저하게 증가시킨다.
다른 스레드들이 성취할 수 있는 유용한 일의 양을 감소시킨다.


-
일부 스레드가 다른 스레드에 비해 상대적으로 충분한 CPU 시간을 얻지 못해서 프로그램이 거의 일을 안 하는 상황에 직면할 때, Thread.yield 메소드를 호출하여 문제를 해결하려고 하면 안 된다.
프로그램이 그럭저럭 돌아갈 테지만 이식성이 없어질 것이다.
똑같은 yield 메소드 호출이 한 JVM 에서는 성능을 향상시키지만, 다른 종류의 JVM 에서는 오히려 성능을 떨어뜨리거나 아무 영향이 없을 수 있다.
따라서 Thread.yield 메소드로는 성능을 시험할 수 없다.
동시적으로 실행 가능한 스레드 개수를 줄이기 위해 애플리케이션을 재구성하는 것이 더 좋은 조치이다.

자바 API 문서에서 Thread.yield. 메소드 명세를 보면 제어를 그 메소드 호출자에게 반환한다고만 나와있을 뿐 그 외 다른 내용이 없다.
근래의 일부 JVM 들은 실제로 그렇게 한다.
그러므로 동시성을 테스트 할 때 Thread.yield 대신 Thread.sleep(1) 을 사용해야 한다.
제어가 곧바로 돌아올 수 있는 Thread.sleep(0) 는 사용하지 말자.


-
스레드 우선 순위(priority)를 조정할 수 있는데,
스레드 우선 순위는 자바 플랫폼에서 가장 이식성이 떨어지는 것 중 하나다.
터무니 없는 것은 아니나, 그럴 필요가 거의 없고 이식성이 떨어진다.
스레드 우선 순위를 조정하여 심각한 활동성(liveness) 문제를 해결하려는 것은 터무니 없는 것이다.
근본적인 원인을 찾아 해결하지 않는 한 그 문제는 또 생길 것이다.


Summary


우리 프로그램의 정확성을 스레드 스케줄러에 의존하지 말자.
스레드 스케줄러에 의존해서 만든 프로그램은 상력하지 않고 이식성도 없다.
Thread.yield 메소드나 스레드 우선 순위에 의존하지 말자.
스레드 우선 순위는 이미 동작 중인 프로그램의 서비스 질을 높이는데 사용될 수 있다.
그러나 거의 동작하지 않는 프로그램을 "고치기 위해" 사용하면 절대 안 된다.





반응형

댓글