2013-04-06 10 views
1

12 개의 스레드가 작업을 실행 중입니다 (Runnable). 본질적으로, 각 스레드는 다음을 수행java - unameary thread wake-ups를 피하십시오.

Runnable r; 

while (true) { 
    synchronized (work) { 
     while (work.isEmpty()) { 
      work.wait(); 
     } 
     r = work.removeFirst(); 
    } 
    r.execute(); 
} 

작업이 다음과 같은 추가 : 새로운 작품을 사용할 수있는 경우

Runnable r = ...; 

synchronized (work) { 
    work.add(r); 
    work.notify(); 
} 

, 그것은 목록에 추가되고 잠금이 통지됩니다. 대기중인 스레드가 있으면 깨어나서이 작업을 실행할 수 있습니다.

여기에 문제가 있습니다. 스레드가 깨어 났을 때 다른 스레드가이 작업을 실행하게 될 가능성이 큽니다. 이것은 후자의 스레드가 이전 작업으로 완료되고 을 다시 입력 할 때 발생합니다. (true) -loop. 작업 작업이 작거나 짧을수록 이러한 일이 발생할 확률이 높습니다.

이것은 아무 것도없는 스레드를 깨우는 것을 의미합니다. 높은 처리량이 필요하기 때문에이 동작으로 인해 성능이 저하 될 것으로 생각됩니다.

어떻게 해결할 수 있습니까? 이론적으로 보류중인 스레드 깨우기 알림을 취소 할 수있는 메커니즘이 필요합니다. 물론 이것은 Java에서는 불가능합니다.

각 스레드에 대한 작업 목록을 소개하려고 생각했습니다. 작업을 하나의 목록으로 푸는 대신 작업 내용을 12 개의 작업 목록에 분산시킵니다. 그러나 이것이 다른 문제를 일으킬 것이라고 나는 믿는다. 예를 들어, 한 스레드는 많은 수의 작업을 보류하고있는 반면, 다른 스레드는 보류중인 작업이 없을 수 있습니다. 본질적으로, 특정 스레드에 작업을 할당하는 솔루션 은 사전에이 매우 복잡하고 차선책이 될 수 있다고 생각합니다.

감사합니다.

+2

나는이 상당한 성능에 영향을 줄 것이라고 의심한다. 또한 표준 ThreadPoolExecutor를 사용하지 않는 이유는 무엇입니까? –

+0

언급을 잊어 버렸습니다 : 내 대상 JVM 1.4입니다. 그러므로 나는 스스로 해결책을 쓰고있다. –

+1

그러면 더 최근의 VM을 사용하게 될 것입니다. 아마도 성능에 더 좋은 영향을 미칩니다. 1.4는 매우 오래되었습니다. 더 이상 지원되지 않습니다. BTW, 가장 좋은 방법은 notifyAll()을 호출하는 것입니다. 그러면 불필요한 웨이크 업이 훨씬 더 자주 발생합니다. 하지만 여전히 최상의 방법입니다. 성능에 중대한 영향을 미쳤다면 아마 그렇지 않을 것입니다. –

답변

2

당신이하고있는 일은 스레드 풀링입니다. 사전 java-5 동시성 프레임 워크, PooledExecutor 클래스를 살펴보십시오. http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html

+0

PooledExecutor에 대해 알고 있지만 내 예제에서는 사용할 수 없습니다. 제 질문은 많이 일반화되었습니다. 내 예에서는 모든 스레드가 매번 병렬로 실행되는 것을 허용하지 않고 예제를 제공합니다. 호기심으로 질문을했습니다. 포인터를 가져 주셔서 감사합니다. –

0

이전 답변 - 또 다른 해결책. 이 질문은 나를 호기심있게 만든다.

여기서 휘발성 부울을 사용하여 검사를 추가했습니다.

쓸데없이 스레드를 깨우는 상황을 완전히 피할 수는 없지만이를 피하는 데 도움이됩니다. 실제로, 나는 이것이 "100ms 후에 가장 잘 수행 될 것"이라는 추가 제한없이 어떻게 완전히 피할 수 있는지 보지 못합니다.

volatile boolean free = false; 

while (true) { 
    synchronized (work) { 
     free = false;    // new rev.2 
     while (work.isEmpty()) { 
      work.wait(); 
     } 
     r = work.removeFirst(); 
    } 
    r.execute(); 
    free = true;  // new 
} 

-

synchronized (work) { 
    work.add(r); 
    if (!free) {   // new 
     work.notify(); 
    }     // new 
    free = false;  // new rev.2 
} 
+0

부울은 아마도 하나의 원자 적 정수 여야합니다. 두 개 이상의 스레드가이를 변경하기 때문입니다. 나는 그 생각을 좋아한다. –

+0

java-1.4에는 원자 정수가 없습니다. 따라서 read-and-set은 원자 적이지 않습니다. – Vitaly

+0

참. 차이점을 벤치마킹하려고 노력할 것입니다. 스레드 A에서 "free = true"는 스레드 B에서 "free = false"로 취소 할 수 있다고 생각합니다. –