22. Executor and thread pool: how to create the correct thread pool? -Concurrency tools

A thread is a heavyweight object, and frequent creation and destruction should be avoided. The thread pool provided by the java SDK is different from other pooled resources, and it does not provide methods for applying threads and releasing threads.

1. Thread pool is a producer-consumer model

The consumer of the thread pool is the producer, and the thread pool itself is the consumer. The following code briefly explains the principle of the thread pool:

//简化的线程池,仅用来说明工作原理
class MyThreadPool {
	//利用阻塞队列实现生产者-消费者模式
	BlockingQueue<Runnable> workQueue;
	//保存内部工作线程
	List<WorkerThread> threads = new ArrayList<>();

	// 构造方法
	MyThreadPool(int poolSize, BlockingQueue<Runnable> workQueue) {
		this.workQueue = workQueue;
		// 创建工作线程
		for (int idx = 0; idx < poolSize; idx++) {
			WorkerThread work = new WorkerThread();
			work.start();
			threads.add(work);
		}
	}

	// 提交任务
	void execute(Runnable command) {
		workQueue.put(command);
	}

	// 工作线程负责消费任务,并执行任务
	class WorkerThread extends Thread {
		public void run() { // (1)
			// 循环取任务并执行
			while (true) {
				Runnable task = workQueue.take();
				task.run();
			}
		}
	}
}

	/** 下面是使用示例 **/
	// 创建有界阻塞队列
	BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
	// 创建线程池
	MyThreadPool pool = new MyThreadPool(10, workQueue);
	// 提交任务
	pool.execute(()->{
	    System.out.println("hello");
	});

2. How to use the thread pool in Java

The core is ThreadPoolExecutor , the most complex constructor:

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                    long keepAliveTime,
                    TimeUnit unit,
                    BlockingQueue<Runnable> workQueue,
                    ThreadFactory threadFactory,
                    RejectedExecutionHandler handler) 
  • corePoolSize, which represents the minimum number of threads held in the thread pool;
  • maximumPoolSize, which represents the maximum number of threads created by the thread pool;
  • keepAliveTime & unit, if a thread has been idle keepAliveTime & unit for so long, and the number of threads in the thread pool is greater than corePoolSize, then the idle thread will be recycled;
  • workQueue, work queue, used to store threads;
  • threadFactory: Customize how to create threads, for example, assign a meaningful name to the thread;
  • handler: Reject strategy for custom tasks. There are four strategies:
    1. CallerRunsPolicy: The thread that submitted the task performs the task itself.
    2. AbortPolicy: The default rejection policy will throw RejectedExecutionException.
    3. DiscardPolicy: Discard the task directly without any exception thrown.
    4. DiscardOldestPolicy: Discarding the oldest task is actually discarding the earliest task that entered the work queue, and then adding the new task to the work queue.

3. What to pay attention to when using thread pool

The most important reason why the static factory Executors of the thread pool is not recommended is that many of the methods provided by Executors use the unbounded LinkedBlockingQueue by default. Unbounded queues can easily lead to OOM under high-load scenarios, and OOM will cause all requests Treatment, this is a fatal problem. Therefore, it is strongly recommended to use bounded queues .

The default rejection strategy should be used with caution. If the tasks handled by the thread pool are very important, it is recommended to customize your own rejection strategy; and in actual work, the custom rejection strategy is often used in conjunction with the demotion strategy.

Although the thread pool provides many methods for exception handling, the safest and simplest solution is to catch all exceptions and handle them as needed. You can refer to the sample code below.

try {
  //业务逻辑
} catch (RuntimeException x) {
  //按需处理
} catch (Throwable x) {
  //按需处理
} 
Published 97 original articles · praised 3 · 10,000+ views

Guess you like

Origin blog.csdn.net/qq_39530821/article/details/102713127