스레드 풀을 사용해야 하는 이유는 무엇인가요?
개인적으로 가장 큰 이유는 짧은 시간 안에 처리해야 할 작업이 많다는 점이라고 생각합니다.
스레드 풀 사용의 장점:
1. 스레드 생성 및 소멸에 소요되는 시간 및 시스템 리소스 오버헤드 감소
2. 스레드 풀을 사용하지 않으면 시스템이 대량의 스레드를 생성하여 시스템 메모리를 모두 소모할 수 있습니다
다음은 Java와 함께 제공되는 여러 스레드 풀입니다.
1. newFixedThreadPool 지정된 수의 작업자 스레드로 스레드 풀을 만듭니다.
작업이 제출될 때마다 작업자 스레드가 생성됩니다. 작업자 스레드 수가 스레드 풀의 초기 최대 개수에 도달하면 제출된 작업이 풀 대기열에 저장됩니다.
2. newCachedThreadPool은 캐시 가능한 스레드 풀을 생성합니다.
이 유형의 스레드 풀의 특징은 다음과 같습니다.
1) 생성되는 작업자 스레드 수에는 거의 제한이 없습니다(실제로는 제한이 있으며 그 수는 Interger입니다. .MAX_VALUE)를 사용하여 스레드 풀에 스레드를 추가합니다.
2) 오랫동안 스레드 풀에 작업이 제출되지 않은 경우, 즉 작업자 스레드가 지정된 시간(기본값은 1분) 동안 유휴 상태인 경우 작업자 스레드가 자동으로 종료됩니다. 종료 후 새 작업을 제출하면 스레드 풀이 작업자 스레드를 다시 생성합니다.
3. newSingleThreadExecutor는 단일 스레드 실행자를 생성합니다. 즉, 작업을 수행하기 위한 고유한 작업자 스레드만 생성합니다. 이 스레드가 비정상적으로 종료되면 순차적 실행을 보장하기 위해 다른 스레드가 이를 대체합니다. 특성).
단일 작업자 스레드의 가장 큰 특징은 다양한 작업의 순차적 실행을 보장할 수 있으며 특정 시간에 여러 스레드가 활성화되지 않는다는 것입니다.
4. newScheduleThreadPool은 고정 길이 스레드 풀을 생성하고 Timer와 유사하게 예약 및 주기적인 작업 실행을 지원합니다.
요약:
1.FixedThreadPool은 스레드 풀의 대표적인 장점으로 프로그램 효율성을 높이고 스레드 생성 시 오버헤드를 줄여준다는 장점이 있습니다. 그러나 스레드 풀이 유휴 상태일 때, 즉 스레드 풀에 실행 가능한 작업이 없으면 작업자 스레드를 해제하지 않고 특정 시스템 리소스도 차지합니다.
2. CachedThreadPool의 특징은 스레드 풀이 유휴 상태일 때, 즉 스레드 풀에 실행 가능한 작업이 없을 때 작업자 스레드를 해제하여 작업자 스레드가 차지한 리소스를 해제한다는 것입니다. 그러나 새로운 작업이 나타나면 새로운 작업자 스레드를 생성해야 하므로 일정량의 시스템 오버헤드가 필요합니다. 또한, CachedThreadPool을 사용할 때에는 작업 개수 조절에 주의해야 한다. 그렇지 않으면 동시에 실행되는 스레드 수가 많아 시스템이 마비될 수 있다.
Java 스레드 풀 ThreadPoolExecutor 사용 예제
package com.sondon.mayi.jpool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class JPoolLearn { private static int produceTaskSleepTime = 3; private static int produceTaskMaxNumber = 20; public void testThreadPoolExecutor(){ /* * ThreadPoolExecutor( * int corePoolSize, //线程池维护线程的最少数量 * int maximumPoolSize, //线程池维护线程的最大数量 * long keepAliveTime, //线程池维护线程所允许的空闲时间 * TimeUnit unit, //线程池维护线程所允许的空闲时间的单位 * BlockingQueue<Runnable> workQueue, //线程池所使用的缓冲队列 * RejectedExecutionHandler handler //线程池对拒绝任务的处理策略 ) */ ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 5, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.DiscardOldestPolicy() ); for (int i = 1; i <= produceTaskMaxNumber; i++) { try { // 产生一个任务,并将其加入到线程池 String task = "task---" + i; threadPool.execute(new ThreadPoolTask(task)); System.out.println("activeCount :"+ threadPool.getActiveCount()); // 便于观察,等待一段时间 Thread.sleep(produceTaskSleepTime); } catch (Exception e) { e.printStackTrace(); } } //查看当前的线程池状况 while(true){ try { Thread.sleep(3000); System.out.println("pool size :"+threadPool.getPoolSize());//线程池中线程数量 System.out.println("active count :"+threadPool.getActiveCount());//线程池中活动的线程数量 } catch (InterruptedException e) { e.printStackTrace(); } } } /** * * @Author 蔡文锋 * @Data_Time 2015年7月25日 下午4:06:28 * @Description { 测试不同线程池模式 } */ public void testNewCachedThreadPool(){ ThreadPoolExecutor threadPool=(ThreadPoolExecutor) Executors.newCachedThreadPool(); // ThreadPoolExecutor threadPool=(ThreadPoolExecutor) Executors.newFixedThreadPool(100); // ThreadPoolExecutor threadPool=(ThreadPoolExecutor) Executors.newScheduledThreadPool(100); // ThreadPoolExecutor threadPool=(ThreadPoolExecutor) Executors.newSingleThreadExecutor(); try { for (int i = 0; i < 100; i++) { // 产生一个任务,并将其加入到线程池 String task = "task---" + i; threadPool.execute(new ThreadPoolTask(task)); System.out.println("activeCount :"); // 便于观察,等待一段时间 Thread.sleep(produceTaskSleepTime); } } catch (InterruptedException e) { e.printStackTrace(); } //查看当前的线程池状况 while(true){ try { Thread.sleep(3000); System.out.println("pool size :"+threadPool.getPoolSize());//线程池中线程数量 System.out.println("active count :"+threadPool.getActiveCount());//线程池中活动的线程数量 } catch (InterruptedException e) { e.printStackTrace(); } } } /** * * @Author 蔡文锋 * @Data_Time 2015年7月25日 下午4:06:58 * @Description { 测试callable与runable方法的区别 } */ public void testNewCachedThreadPool_callable(){ ExecutorService es=Executors.newFixedThreadPool(10); try { // String result=es.submit(new MyCallable<String>()).get(); // System.out.println("callable result :"+result); String result=(String) es.submit(new ThreadPoolTask("")).get(); System.out.println("runable result :"+result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } public static void main(String[] args) { new JPoolLearn().testNewCachedThreadPool(); } } /** * 线程池执行的任务 */ class ThreadPoolTask implements Runnable { private static int consumeTaskSleepTime = 2000; // 保存任务所需要的数据 private Object threadPoolTaskData; ThreadPoolTask(Object tasks) { this.threadPoolTaskData = tasks; } public void run() { System.out.println("start .." + threadPoolTaskData); try { // Sleep 2秒 模拟耗时操作 Thread.sleep(consumeTaskSleepTime); } catch (Exception e) { e.printStackTrace(); } threadPoolTaskData = null; } public Object getTask() { return this.threadPoolTaskData; } } /** * * @Project : JPool * @Package : com.sondon.mayi.jpool * @Class : MyCallable * @param <T> */ class MyCallable<T> implements Callable<T>{ @Override public T call() throws Exception { System.out.println("开始执行Callable"); return (T) "测试callable接口"; } }
Java 스레드 풀의 작동 특성을 소개하는 더 많은 예제를 보려면 PHP 중국어 웹사이트에서 관련 기사를 주목하세요!