2012-09-17 4 views
2

스레드 풀 디자인 패턴 (병렬로 수행 할 많은 작은 작업)의 이점이있는 작업이 있습니다. 나는 처음부터 순진한 쓰레드 풀을 구현했다. n Runnables는 대기열이 비워 질 때까지 같은 ConcurrentLinkedQueue에서 작업 단위를 모두 가져온다. 그런 다음 "안녕하세요, Java로 Executor를 시험해 봅니다. 아마도 내 의도적으로 설계된 시스템보다 테스트가 잘되고 신뢰할 수 있기 때문입니다." 문제 : 구현시 각 스레드는 대기열이 비어있을 때까지 (!queue.isEmpty())을 사용하여 지속되고 스레드가없는 객체가 아닌 자체 인스턴스를 얻습니다.이 작업을 구성하는 데 많은 시간이 걸리는 SlowObject foo이라고합시다. Runnable을 모두 Executor의 풀로 전달하려고 시도하면 스레드 안전하지 않기 때문에 시간이 비효율적 인 개체의 인스턴스가 실패합니다. 각 Runnable에 대해 SlowObject의 새 인스턴스를 만드는 것은 비용이 많이 들기 때문에 바람직하지 않습니다.Java Executors 및 스레드 (작업 단위가 아닌) 객체마다?

"얼마나 많은 스레드를 사용하고 있습니까? 각 스레드마다 하나의 SlowObject을 만들고 Runnables가 사용중인 스레드를 탐지하고 사용할 올바른 개체를 찾으십시오." 이것은 부서지기 쉽고 오류가 발생하기 쉬운 것처럼 들리지만, 대신 내가 봐야 할 디자인 패턴이 무엇인지 확실하지 않습니다.

+5

[ThreadLocal] (http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html)을보십시오 –

+0

신속하게 복사본을 만들 수 없습니까? '슬로우 객체 (SlowObject) '? 그것으로 들어갈 필요가있는 데이터를 찾는 것이 느리거나 모든 데이터를 가지고 나면 객체를 만드는 것이 느려 집니까? –

+0

@ coding.mof. 답으로 의견을 쓰십시오. IMHO 올바른 대답입니다. – AlexR

답변

3

Java는 ThreadLocal 변수의 개념을 제공합니다.
Runnable 내에서 사용할 수 있습니다.

public class MyJob implements Runnable { 
    private static final ThreadLocal <SlowObject> threadLocal = 
     new ThreadLocal <SlowObject>() { 
     @Override protected SlowObject initialValue() { 
      // construct and return your SlowObject 
     } 
     }; 

    public void run() { 
     // work with threadLocal.get() 
    } 
    } 

따라서 Runnable을 실행하는 각 스레드에 대해 SlowObject 클래스의 단일 인스턴스 만 만들어집니다.

4

리소스 풀을 사용하는 것이 좋습니다. 다음과 같이 사용하십시오.

public class SlowObjectPool { 
    private static final int POOL_SIZE = 10; 
    private BlockingQueue<SlowObject> slowObjectQueue = new ArrayBlockingQueue(POOL_SIZE); 

    public SlowObjectPool() { 
     for (int i = 0; i < POOL_SIZE; i++) { 
      slowObjectQueue.put(new SlowObject()); 
     } 
    } 

    public SlowObject take() throws InterruptedException { 
     return slowObjectQueue.take(); 
    } 

    public void release(SlowObject slowObject) { 
     // TODO You may want to log a warning if this is false 
     slowObjectQueue.offer(slowObject); 
    } 
} 

이 기능을 싱글 톤으로 만들 수도 있습니다. 그런 다음보다 Runnable에 : 풀 처음 동적으로 만드는 대신 생성 될 때

public class MyRunnable implements Runnable { 

    private SlowObjectPool pool; 

    public MyRunnable(SlowObjectPool pool) { 
     this.pool = pool; 
    } 

    @Override 
    public void run() { 
     // The next line blocks until a SlowObject is available 
     SomeObject someObject = null; 
     try { 
      someObject = pool.take() 
      // Do something with someObject 
     } catch (InterruptedException ex) { 
      // Thread is being ended, allow to end 
     } finally { 
      if (someObject != null) 
       pool.release(someObject); 
     } 
    } 
} 

이 번에 모든 개체를 생성합니다, 당신보다 Runnable의 방법 없음 SomeObject 인스턴스를 생성 할 때까지 기다릴 필요가 없습니다.