Custom JAVA thread pool rejection policy

Recently, I have been troubled by the consumption business of the queue. Let’s talk about the business situation first.

The data generated by module A is passed to module B for processing through the queue, but the data comes from timed tasks, often tens of thousands or more in an instant, and the consumption of module B has limited speed control and limited capacity (the thread pool used by the consumer business), sure It takes time to digest.

Then a question that arises is which rejection policy of the thread pool to choose?

First, let's talk about the four rejection strategies of the thread pool:

  1. AbortPolicy: Throws an exception directly.
  2. CallerRunsPolicy: Only use the thread of the caller to run tasks.
  3. DiscardOldestPolicy: Discard the oldest task in the queue and execute the current task.
  4. DiscardPolicy: Do not process, discard.

The initial intuitive feeling is that you can't lose messages. Use 2, and the main thread will follow the business.

After a long time, I found a problem. Once the main thread (let's say it, to be precise, the thread that starts the thread pool) runs the task, even if the thread in the thread pool finishes running the task, it will not enter the task again, and it's hungry. Until the main thread runs a business, it can continue to consume and assign it to the thread pool task.

The problem is obvious. The business process is time-consuming, and the main thread is occupied. Once the thread pool finishes its work, it cannot do anything, waiting for the main thread to consume the queued data for new tasks.

I can't bear it, but after analyzing the other three policies, AbortPolicy throws an exception directly, but I still don't know what to do; DiscardOldestPolicy discards old tasks and messages, no; DiscardPolicy discards, definitely no.

So I looked at the source code of the rejection policy and found that these classes of rejection policy are really concise (there are only two methods), uniformly implement the RejectedExecutionHandler interface, implement the rejectedExecution method (a few lines of code...), and have its own construction method (empty ).

Then analyze your own business requirements, and summarize: after the blocking queue of the thread pool is full, the main thread does nothing, and when the blocking queue is full, the task is thrown to the thread pool.

Looking at the source code, I found that the blocking queue just has a remainingCapacity interface. You can see what it means by looking at the literal meaning. However, in line with the rigorous attitude of our apes, we will continue to look at the interface source code. number). Then the main thread only needs to keep getting the free number, and it will continue to get it if it is 0, until it is not 0. code show as below:

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
     if (!e.isShutdown()) {
          while (e.getQueue().remainingCapacity() == 0);
          e.execute(r);
     }
 }

Runnable r : main thread

ThreadPoolExecutor e: thread pool

It is recommended to look at the implementation of the other four strategies first.

I thought this problem was more complicated, but it turned out to be solved with only a few lines of code. I don't know if there are any pits...

ps: If there is a problem, please correct the exchange. If there is a better solution, welcome guidance.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326606453&siteId=291194637