logo

Java 스레드 풀

자바 스레드 풀 작업을 기다리고 여러 번 재사용되는 작업자 스레드 그룹을 나타냅니다.

스레드 풀의 경우 고정 크기 스레드 그룹이 생성됩니다. 스레드 풀에서 스레드를 꺼내 서비스 공급자가 작업을 할당합니다. 작업이 완료된 후 스레드는 다시 스레드 풀에 포함됩니다.

스레드 풀 방법

newFixedThreadPool(int s): 이 메서드는 고정 크기 s의 스레드 풀을 생성합니다.

newCachedThreadPool(): 이 메서드는 필요할 때 새 스레드를 생성하지만 사용할 수 있을 때마다 이전에 생성된 스레드를 계속 사용하는 새 스레드 풀을 생성합니다.

새로운SingleThreadExecutor(): 이 메서드는 새 스레드를 생성합니다.

Java 스레드 풀의 장점

더 나은 성능 새로운 스레드를 생성할 필요가 없기 때문에 시간이 절약됩니다.

실시간 사용량

컨테이너가 요청을 처리하기 위해 스레드 풀을 생성하는 서블릿 및 JSP에서 사용됩니다.

Java 스레드 풀의 예

ExecutorService 및 Executors를 사용하는 Java 스레드 풀의 간단한 예를 살펴보겠습니다.

파일: WorkerThread.java

 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class WorkerThread implements Runnable { private String message; public WorkerThread(String s){ this.message=s; } public void run() { System.out.println(Thread.currentThread().getName()+' (Start) message = '+message); processmessage();//call processmessage method that sleeps the thread for 2 seconds System.out.println(Thread.currentThread().getName()+' (End)');//prints thread name } private void processmessage() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } 

파일: TestThreadPool.java

 public class TestThreadPool { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(5);//creating a pool of 5 threads for (int i = 0; i <10; i++) { runnable worker="new" workerthread('' + i); executor.execute(worker); calling execute method of executorservice } executor.shutdown(); while (!executor.isterminated()) system.out.println('finished all threads'); < pre> <p> <strong>Output:</strong> </p> <pre>pool-1-thread-1 (Start) message = 0 pool-1-thread-2 (Start) message = 1 pool-1-thread-3 (Start) message = 2 pool-1-thread-5 (Start) message = 4 pool-1-thread-4 (Start) message = 3 pool-1-thread-2 (End) pool-1-thread-2 (Start) message = 5 pool-1-thread-1 (End) pool-1-thread-1 (Start) message = 6 pool-1-thread-3 (End) pool-1-thread-3 (Start) message = 7 pool-1-thread-4 (End) pool-1-thread-4 (Start) message = 8 pool-1-thread-5 (End) pool-1-thread-5 (Start) message = 9 pool-1-thread-2 (End) pool-1-thread-1 (End) pool-1-thread-4 (End) pool-1-thread-3 (End) pool-1-thread-5 (End) Finished all threads </pre> download this example <h2>Thread Pool Example: 2</h2> <p>Let&apos;s see another example of the thread pool.</p> <p> <strong>FileName:</strong> ThreadPoolExample.java</p> <pre> // important import statements import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.text.SimpleDateFormat; class Tasks implements Runnable { private String taskName; // constructor of the class Tasks public Tasks(String str) { // initializing the field taskName taskName = str; } // Printing the task name and then sleeps for 1 sec // The complete process is getting repeated five times public void run() { try { for (int j = 0; j <= 5; j++) { if (j="=" 0) date dt="new" date(); simpledateformat sdf="new" simpledateformat('hh : mm ss'); prints the initialization time for every task system.out.println('initialization name: '+ taskname + '=" + sdf.format(dt)); } else { Date dt = new Date(); SimpleDateFormat sdf = new SimpleDateFormat(" hh execution system.out.println('time of is complete.'); } catch(interruptedexception ie) ie.printstacktrace(); public class threadpoolexample maximum number threads in thread pool static final int max_th="3;" main method void main(string argvs[]) creating five new tasks runnable rb1="new" tasks('task 1'); rb2="new" 2'); rb3="new" 3'); rb4="new" 4'); rb5="new" 5'); a with size fixed executorservice pl="Executors.newFixedThreadPool(MAX_TH);" passes objects to execute (step 3) pl.execute(rb1); pl.execute(rb2); pl.execute(rb3); pl.execute(rb4); pl.execute(rb5); shutdown pl.shutdown(); < pre> <p> <strong>Output:</strong> </p> <pre> Initialization time for the task name: task 1 = 06 : 13 : 02 Initialization time for the task name: task 2 = 06 : 13 : 02 Initialization time for the task name: task 3 = 06 : 13 : 02 Time of execution for the task name: task 1 = 06 : 13 : 04 Time of execution for the task name: task 2 = 06 : 13 : 04 Time of execution for the task name: task 3 = 06 : 13 : 04 Time of execution for the task name: task 1 = 06 : 13 : 05 Time of execution for the task name: task 2 = 06 : 13 : 05 Time of execution for the task name: task 3 = 06 : 13 : 05 Time of execution for the task name: task 1 = 06 : 13 : 06 Time of execution for the task name: task 2 = 06 : 13 : 06 Time of execution for the task name: task 3 = 06 : 13 : 06 Time of execution for the task name: task 1 = 06 : 13 : 07 Time of execution for the task name: task 2 = 06 : 13 : 07 Time of execution for the task name: task 3 = 06 : 13 : 07 Time of execution for the task name: task 1 = 06 : 13 : 08 Time of execution for the task name: task 2 = 06 : 13 : 08 Time of execution for the task name: task 3 = 06 : 13 : 08 task 2 is complete. Initialization time for the task name: task 4 = 06 : 13 : 09 task 1 is complete. Initialization time for the task name: task 5 = 06 : 13 : 09 task 3 is complete. Time of execution for the task name: task 4 = 06 : 13 : 10 Time of execution for the task name: task 5 = 06 : 13 : 10 Time of execution for the task name: task 4 = 06 : 13 : 11 Time of execution for the task name: task 5 = 06 : 13 : 11 Time of execution for the task name: task 4 = 06 : 13 : 12 Time of execution for the task name: task 5 = 06 : 13 : 12 Time of execution for the task name: task 4 = 06 : 13 : 13 Time of execution for the task name: task 5 = 06 : 13 : 13 Time of execution for the task name: task 4 = 06 : 13 : 14 Time of execution for the task name: task 5 = 06 : 13 : 14 task 4 is complete. task 5 is complete. </pre> <p> <strong>Explanation:</strong> It is evident by looking at the output of the program that tasks 4 and 5 are executed only when the thread has an idle thread. Until then, the extra tasks are put in the queue.</p> <p>The takeaway from the above example is when one wants to execute 50 tasks but is not willing to create 50 threads. In such a case, one can create a pool of 10 threads. Thus, 10 out of 50 tasks are assigned, and the rest are put in the queue. Whenever any thread out of 10 threads becomes idle, it picks up the 11<sup>th </sup>task. The other pending tasks are treated the same way.</p> <h2>Risks involved in Thread Pools</h2> <p>The following are the risk involved in the thread pools.</p> <p> <strong>Deadlock:</strong> It is a known fact that deadlock can come in any program that involves multithreading, and a thread pool introduces another scenario of deadlock. Consider a scenario where all the threads that are executing are waiting for the results from the threads that are blocked and waiting in the queue because of the non-availability of threads for the execution.</p> <p> <strong>Thread Leakage:</strong> Leakage of threads occurs when a thread is being removed from the pool to execute a task but is not returning to it after the completion of the task. For example, when a thread throws the exception and the pool class is not able to catch this exception, then the thread exits and reduces the thread pool size by 1. If the same thing repeats a number of times, then there are fair chances that the pool will become empty, and hence, there are no threads available in the pool for executing other requests.</p> <p> <strong>Resource Thrashing:</strong> A lot of time is wasted in context switching among threads when the size of the thread pool is very large. Whenever there are more threads than the optimal number may cause the starvation problem, and it leads to resource thrashing.</p> <h2>Points to Remember</h2> <p>Do not queue the tasks that are concurrently waiting for the results obtained from the other tasks. It may lead to a deadlock situation, as explained above.</p> <p>Care must be taken whenever threads are used for the operation that is long-lived. It may result in the waiting of thread forever and will finally lead to the leakage of the resource.</p> <p>In the end, the thread pool has to be ended explicitly. If it does not happen, then the program continues to execute, and it never ends. Invoke the shutdown() method on the thread pool to terminate the executor. Note that if someone tries to send another task to the executor after shutdown, it will throw a RejectedExecutionException.</p> <p>One needs to understand the tasks to effectively tune the thread pool. If the given tasks are contrasting, then one should look for pools for executing different varieties of tasks so that one can properly tune them.</p> <p>To reduce the probability of running JVM out of memory, one can control the maximum threads that can run in JVM. The thread pool cannot create new threads after it has reached the maximum limit.</p> <p>A thread pool can use the same used thread if the thread has finished its execution. Thus, the time and resources used for the creation of a new thread are saved.</p> <h2>Tuning the Thread Pool</h2> <p>The accurate size of a thread pool is decided by the number of available processors and the type of tasks the threads have to execute. If a system has the P processors that have only got the computation type processes, then the maximum size of the thread pool of P or P + 1 achieves the maximum efficiency. However, the tasks may have to wait for I/O, and in such a scenario, one has to take into consideration the ratio of the waiting time (W) and the service time (S) for the request; resulting in the maximum size of the pool P * (1 + W / S) for the maximum efficiency.</p> <h2>Conclusion</h2> <p>A thread pool is a very handy tool for organizing applications, especially on the server-side. Concept-wise, a thread pool is very easy to comprehend. However, one may have to look at a lot of issues when dealing with a thread pool. It is because the thread pool comes with some risks involved it (risks are discussed above).</p> <hr></=></pre></10;>
이 예제를 다운로드하세요

스레드 풀 예: 2

스레드 풀의 또 다른 예를 살펴보겠습니다.

파일 이름: ThreadPoolExample.java

리눅스 명령
 // important import statements import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.text.SimpleDateFormat; class Tasks implements Runnable { private String taskName; // constructor of the class Tasks public Tasks(String str) { // initializing the field taskName taskName = str; } // Printing the task name and then sleeps for 1 sec // The complete process is getting repeated five times public void run() { try { for (int j = 0; j <= 5; j++) { if (j="=" 0) date dt="new" date(); simpledateformat sdf="new" simpledateformat(\'hh : mm ss\'); prints the initialization time for every task system.out.println(\'initialization name: \'+ taskname + \'=" + sdf.format(dt)); } else { Date dt = new Date(); SimpleDateFormat sdf = new SimpleDateFormat(" hh execution system.out.println(\'time of is complete.\'); } catch(interruptedexception ie) ie.printstacktrace(); public class threadpoolexample maximum number threads in thread pool static final int max_th="3;" main method void main(string argvs[]) creating five new tasks runnable rb1="new" tasks(\'task 1\'); rb2="new" 2\'); rb3="new" 3\'); rb4="new" 4\'); rb5="new" 5\'); a with size fixed executorservice pl="Executors.newFixedThreadPool(MAX_TH);" passes objects to execute (step 3) pl.execute(rb1); pl.execute(rb2); pl.execute(rb3); pl.execute(rb4); pl.execute(rb5); shutdown pl.shutdown(); < pre> <p> <strong>Output:</strong> </p> <pre> Initialization time for the task name: task 1 = 06 : 13 : 02 Initialization time for the task name: task 2 = 06 : 13 : 02 Initialization time for the task name: task 3 = 06 : 13 : 02 Time of execution for the task name: task 1 = 06 : 13 : 04 Time of execution for the task name: task 2 = 06 : 13 : 04 Time of execution for the task name: task 3 = 06 : 13 : 04 Time of execution for the task name: task 1 = 06 : 13 : 05 Time of execution for the task name: task 2 = 06 : 13 : 05 Time of execution for the task name: task 3 = 06 : 13 : 05 Time of execution for the task name: task 1 = 06 : 13 : 06 Time of execution for the task name: task 2 = 06 : 13 : 06 Time of execution for the task name: task 3 = 06 : 13 : 06 Time of execution for the task name: task 1 = 06 : 13 : 07 Time of execution for the task name: task 2 = 06 : 13 : 07 Time of execution for the task name: task 3 = 06 : 13 : 07 Time of execution for the task name: task 1 = 06 : 13 : 08 Time of execution for the task name: task 2 = 06 : 13 : 08 Time of execution for the task name: task 3 = 06 : 13 : 08 task 2 is complete. Initialization time for the task name: task 4 = 06 : 13 : 09 task 1 is complete. Initialization time for the task name: task 5 = 06 : 13 : 09 task 3 is complete. Time of execution for the task name: task 4 = 06 : 13 : 10 Time of execution for the task name: task 5 = 06 : 13 : 10 Time of execution for the task name: task 4 = 06 : 13 : 11 Time of execution for the task name: task 5 = 06 : 13 : 11 Time of execution for the task name: task 4 = 06 : 13 : 12 Time of execution for the task name: task 5 = 06 : 13 : 12 Time of execution for the task name: task 4 = 06 : 13 : 13 Time of execution for the task name: task 5 = 06 : 13 : 13 Time of execution for the task name: task 4 = 06 : 13 : 14 Time of execution for the task name: task 5 = 06 : 13 : 14 task 4 is complete. task 5 is complete. </pre> <p> <strong>Explanation:</strong> It is evident by looking at the output of the program that tasks 4 and 5 are executed only when the thread has an idle thread. Until then, the extra tasks are put in the queue.</p> <p>The takeaway from the above example is when one wants to execute 50 tasks but is not willing to create 50 threads. In such a case, one can create a pool of 10 threads. Thus, 10 out of 50 tasks are assigned, and the rest are put in the queue. Whenever any thread out of 10 threads becomes idle, it picks up the 11<sup>th </sup>task. The other pending tasks are treated the same way.</p> <h2>Risks involved in Thread Pools</h2> <p>The following are the risk involved in the thread pools.</p> <p> <strong>Deadlock:</strong> It is a known fact that deadlock can come in any program that involves multithreading, and a thread pool introduces another scenario of deadlock. Consider a scenario where all the threads that are executing are waiting for the results from the threads that are blocked and waiting in the queue because of the non-availability of threads for the execution.</p> <p> <strong>Thread Leakage:</strong> Leakage of threads occurs when a thread is being removed from the pool to execute a task but is not returning to it after the completion of the task. For example, when a thread throws the exception and the pool class is not able to catch this exception, then the thread exits and reduces the thread pool size by 1. If the same thing repeats a number of times, then there are fair chances that the pool will become empty, and hence, there are no threads available in the pool for executing other requests.</p> <p> <strong>Resource Thrashing:</strong> A lot of time is wasted in context switching among threads when the size of the thread pool is very large. Whenever there are more threads than the optimal number may cause the starvation problem, and it leads to resource thrashing.</p> <h2>Points to Remember</h2> <p>Do not queue the tasks that are concurrently waiting for the results obtained from the other tasks. It may lead to a deadlock situation, as explained above.</p> <p>Care must be taken whenever threads are used for the operation that is long-lived. It may result in the waiting of thread forever and will finally lead to the leakage of the resource.</p> <p>In the end, the thread pool has to be ended explicitly. If it does not happen, then the program continues to execute, and it never ends. Invoke the shutdown() method on the thread pool to terminate the executor. Note that if someone tries to send another task to the executor after shutdown, it will throw a RejectedExecutionException.</p> <p>One needs to understand the tasks to effectively tune the thread pool. If the given tasks are contrasting, then one should look for pools for executing different varieties of tasks so that one can properly tune them.</p> <p>To reduce the probability of running JVM out of memory, one can control the maximum threads that can run in JVM. The thread pool cannot create new threads after it has reached the maximum limit.</p> <p>A thread pool can use the same used thread if the thread has finished its execution. Thus, the time and resources used for the creation of a new thread are saved.</p> <h2>Tuning the Thread Pool</h2> <p>The accurate size of a thread pool is decided by the number of available processors and the type of tasks the threads have to execute. If a system has the P processors that have only got the computation type processes, then the maximum size of the thread pool of P or P + 1 achieves the maximum efficiency. However, the tasks may have to wait for I/O, and in such a scenario, one has to take into consideration the ratio of the waiting time (W) and the service time (S) for the request; resulting in the maximum size of the pool P * (1 + W / S) for the maximum efficiency.</p> <h2>Conclusion</h2> <p>A thread pool is a very handy tool for organizing applications, especially on the server-side. Concept-wise, a thread pool is very easy to comprehend. However, one may have to look at a lot of issues when dealing with a thread pool. It is because the thread pool comes with some risks involved it (risks are discussed above).</p> <hr></=>

설명: 작업 4와 5는 스레드에 유휴 스레드가 있을 때만 실행된다는 것이 프로그램의 출력을 보면 분명해집니다. 그때까지는 추가 작업이 대기열에 추가됩니다.

위의 예에서 알 수 있는 점은 50개의 작업을 실행하고 싶지만 50개의 스레드를 생성할 의향이 없는 경우입니다. 이러한 경우 10개의 스레드 풀을 만들 수 있습니다. 따라서 50개의 작업 중 10개가 할당되고 나머지는 대기열에 배치됩니다. 10개 스레드 중 하나라도 유휴 상태가 될 때마다 11개 스레드를 선택합니다.일. 다른 보류 중인 작업도 동일한 방식으로 처리됩니다.

스레드 풀과 관련된 위험

스레드 풀과 관련된 위험은 다음과 같습니다.

이중 자물쇠: 멀티스레딩과 관련된 모든 프로그램에서 교착 상태가 발생할 수 있으며 스레드 풀은 교착 상태의 또 다른 시나리오를 가져온다는 것은 알려진 사실입니다. 실행 중인 모든 스레드가 실행에 스레드를 사용할 수 없기 때문에 차단된 스레드의 결과를 기다리고 큐에 대기 중인 시나리오를 생각해 보십시오.

스레드 누출: 스레드 누출은 스레드가 작업을 실행하기 위해 풀에서 제거되었지만 작업 완료 후 반환되지 않을 때 발생합니다. 예를 들어, 스레드가 예외를 발생시키고 풀 클래스가 이 예외를 포착할 수 없으면 스레드가 종료되고 스레드 풀 크기가 1만큼 줄어듭니다. 동일한 일이 여러 번 반복되면 다음과 같은 가능성이 있습니다. 풀은 비어 있게 되며, 따라서 다른 요청을 실행하기 위해 풀에 사용할 수 있는 스레드가 없습니다.

리소스 스래싱: 스레드 풀의 크기가 매우 클 경우 스레드 간 컨텍스트 전환에 많은 시간이 낭비됩니다. 최적의 수보다 더 많은 스레드가 있을 때마다 기아 문제가 발생할 수 있으며 이는 리소스 스래싱으로 이어집니다.

기억해야 할 점

다른 작업에서 얻은 결과를 동시에 기다리는 작업을 대기열에 추가하지 마세요. 위에서 설명한 대로 교착 상태가 발생할 수 있습니다.

수명이 긴 작업에 스레드를 사용할 때마다 주의를 기울여야 합니다. 이로 인해 스레드가 영원히 대기하게 될 수 있으며 결국 리소스 누출로 이어질 수 있습니다.

결국 스레드 풀은 명시적으로 종료되어야 합니다. 만약 발생하지 않는다면, 프로그램은 계속해서 실행되며 끝나지 않습니다. 스레드 풀에서 shutdown() 메서드를 호출하여 실행기를 종료합니다. 누군가 종료 후 실행기에 다른 작업을 보내려고 하면 RejectedExecutionException이 발생합니다.

스레드 풀을 효과적으로 조정하려면 작업을 이해해야 합니다. 주어진 작업이 대조되는 경우 적절하게 조정할 수 있도록 다양한 종류의 작업을 실행하기 위한 풀을 찾아야 합니다.

JVM이 메모리 부족으로 실행될 가능성을 줄이기 위해 JVM에서 실행될 수 있는 최대 스레드를 제어할 수 있습니다. 스레드 풀은 최대 제한에 도달한 후에는 새 스레드를 생성할 수 없습니다.

스레드 풀은 스레드가 실행을 마친 경우 사용된 동일한 스레드를 사용할 수 있습니다. 따라서 새 스레드를 생성하는 데 사용되는 시간과 리소스가 절약됩니다.

스레드 풀 조정

스레드 풀의 정확한 크기는 사용 가능한 프로세서 수와 스레드가 실행해야 하는 작업 유형에 따라 결정됩니다. 시스템에 계산 유형 프로세스만 있는 P개의 프로세서가 있는 경우 스레드 풀의 최대 크기인 P 또는 P + 1이 최대 효율성을 달성합니다. 그러나 작업이 I/O를 기다려야 할 수도 있으며, 이러한 시나리오에서는 요청에 대한 대기 시간(W)과 서비스 시간(S)의 비율을 고려해야 합니다. 최대 효율을 위해 풀의 최대 크기 P * (1 + W / S)가 발생합니다.

결론

스레드 풀은 특히 서버 측에서 애플리케이션을 구성하는 데 매우 편리한 도구입니다. 개념적으로 스레드 풀은 이해하기 매우 쉽습니다. 그러나 스레드 풀을 다룰 때 많은 문제를 살펴봐야 할 수도 있습니다. 스레드 풀에는 일부 위험이 수반되기 때문입니다(위험은 위에서 논의됨).

xd가 무슨 뜻인가요?