2010-02-24 5 views
49

나는 항상 스레드를 만드는 것이 비싸다는 것을 읽었습니다.
또한 스레드를 다시 실행할 수 없다는 것도 알고 있습니다.자바 스레드 재사용

나는 Executors 클래스의 문서에 참조 :

는 필요에 따라 새 스레드를 작성하는 thread 풀을 작성하지만, 사용할 수있는 경우에는 이전에 구축 된 thread를 재사용합니다.

'재사용'이라는 단어를 유의하십시오.

스레드 풀의 '재사용'스레드는 어떻게됩니까?

답변

44

나는 내가 지금 여기 내 더 이상 대답의 당신을 confuzzabling 무슨 이해 생각

스레드 풀의 '재사용'스레드는 어떻게됩니까?

어떤 일이 일어나고은 단일 스레드는 일반적으로 Runnable로 전달 여러 가지 작업을 (처리하는 데 사용하지만, 이것이 당신의 '집행자'프레임 워크에 의존 할 수 있다는 것입니다 : 기본 집행이 Runnable을 수락,하지만 당신은 당신의 자신의 "유언 집행을 쓸 수 "/ 스레드 풀은 Runnable [예 : CancellableRunnable]보다 복잡한 것을 받아들입니다.

구현시 기본값으로 ExecutorService 구현에서 스레드가 여전히 사용 중 종료되는 경우 자동으로 새 스레드로 대체되지만 이는 다시 '재사용'이 아닙니다. 이 경우에는 "재사용"이 없습니다.

그래서 당신은 당신이 실행기에 원하는만큼 Runnable를 전달할 수 있습니다 각 Runnablerun() 방법은 한 번만 호출해야한다 두 번 자바 스레드에 start()를 호출 할 수는 없지만 사실이다.

당신은 run() 6 회가 (실제적으로 정확히 6 RunnableThread마다 실행됩니다하지만 그 세부 사항이다가 보장 할 것), 예를 들어, 각 작업자 스레드가 호출 할 수있다 (30) Runnable 자바 Thread 5 및 전달할 수 있습니다.

이 예제에서 start()은 6 번 호출되었을 것입니다.

Thread.start() 자바 독에서 : Runnable가 대기열에서 제거해야한다

* Causes this thread to begin execution; the Java Virtual Machine 
* calls the <code>run</code> method of this thread. 

하지만 각 스레드의 run() 방법 안에이 6 start()Thread정확히 한 번만run() 메서드를 호출합니다 각각 각 Runnablerun() 방법이 호출 될 예정입니다. 따라서 각 스레드는 여러 개의 Runnable을 처리 할 수 ​​있습니다. 그것이 "스레드 재사용"에 의해 참조됩니다. 자신의 스레드 풀을 할

한 가지 방법은보다 Runnable를 대기열과는 다음 Runnable (또는 블록) 대기열에서 제외하는 Runnablerun() 방법을 처리 완료 된 후에는, 스레드의 각이있는에 차단 큐를 사용하는 것입니다 run() 방법을 실행 한 다음 헹구고 반복하십시오.

나는 혼란의 일부를 추측 기본 스레드 풀 Runnable을하는 동안 Thread가 실행 가능한의 run() 메소드가 호출되는 Runnablestart()를 호출에 걸린다는 사실에서 온다 (그리고는 약간 혼동이) .

+22

tl; dr 스레드 풀 스레드는 기본적으로 제출 된 작업을 대기열에서 끌어내는 실행 루프입니다.스레드는 작업을 처리 할 때 실행을 멈추지 않고 다음 스레드가 대기열에 제출 될 때까지 대기합니다. 그들은 끊임없이 달리기 때문에 질문에서 묻는대로 결코 '재방송'을하지 않습니다. – Sogger

4

스레드 풀은 내부 작업 큐에서 작업을 수행 할 수있는 여러 고정 작업자 스레드로 구성됩니다. 따라서 하나의 작업이 끝나면 스레드는 이 아니며이 아니라 다음 작업을 기다립니다. 스레드를 중단하면 자동으로 대체됩니다.

자세한 내용은 documentation을 참조하십시오.

-4

thread이 완료되면 다시 사용할 수 있는지 확인하십시오. isAlive() 또는 비슷한 것을 호출하여 실행되지 않는지 확인할 수 있습니다.

수정 : 누군가 thread을 일시 중지 한 경우 다시 시작할 수 없습니다. 나는 그것이 정상적으로 끝난다면 시작할 수없는 이유는 없습니다. 하지만 의심의 여지가 있으며 은 재사용 할 수 없다고 말합니다.

+4

@fastcodejava : 스레드가 완료되면 * start() *를 다시 호출 할 수 없으므로 * IllegalThreadStateException *이 발생합니다. – SyntaxT3rr0r

12

run 스레드 풀의 스레드 방법은 단일 작업 실행으로 만 구성되지 않습니다. 스레드 풀의 스레드에 대한 run 메서드는 루프를 포함합니다. 작업을 대기열에서 꺼내어 작업이 완료되면 작업을 실행하고 (완료되면 을 루프으로 되돌림) 다음 작업을 가져옵니다. run 메서드는 스레드가 더 이상 필요하지 않을 때까지 완료되지 않습니다.

편집 추가 할 :

여기

ThreadPoolExecutor에서 Worker 내부 클래스의 run 방법이다. (분명, 또는 특별히 '재사용'에 중점을두고 그 질문을하지 않을) 용어가 작은 약간 오해의 소지가있다 :

696:   /** 
697:   * Main run loop 
698:   */ 
699:   public void run() { 
700:    try { 
701:     Runnable task = firstTask; 
702:     firstTask = null; 
703:     while (task != null || (task = getTask()) != null) { 
704:      runTask(task); 
705:      task = null; // unnecessary but can help GC 
706:     } 
707:    } finally { 
708:     workerDone(this); 
709:    } 
710:   } 
+0

@Mike Daniels : 정확히 말하자면, "task = null;"*을 지정하고 "* 불필요하지만 GC를 도울 수 있습니다"*라는 Sun 코드를 좋아해야합니다. 당신은 코드를 여기에 올리면 groupthinkers에 의해 당신이 얼마나 무의미한 지 알려주는 목구멍에 뛰어들 것입니다.) – SyntaxT3rr0r

+5

@Wizard : 실제로 불필요한 것은 아닙니다 - (이상한) 작업 테스트! = 루프에 null이 있으면 동일한 작업을 계속 처리하지 못하게해야합니다. 루프가 더 통상적 인 경우에도, 오랫동안 getTask() 블록을 사용하면 작업의 GC가 동일한 시간 동안 지연 될 수 있기 때문에 nulling 작업이 좋을 것입니다. –

+0

@ Software Monkey : 두 번째 요점에 대해 매우 통찰력이 있습니다. 'getTask'는 아마 타임 아웃을 가진 블로킹 큐에서 빠져 나옵니다. 타임 아웃의 전체 기간 동안 차단 될 수 있습니다. 작업에 많은 필드가있는 경우 (작업에 전달 된 매개 변수 용) 이전 GC가 도움이됩니다. –

0

스레드 풀은 자체 스레드를 생성하고 스레드에 대해 자체의 영리한 Runnables를 제공합니다. 그러한 Runnable는 결코 종료하지 않고 Callable가 그 큐에 존재할 때까지 큐 (대기())로 동기합니다. 그 일이 발생하면 (자) 통지를받습니다. Runnable는 큐로부터 Callable를 실행 해, 시나리오 전체가 다시 반복합니다.