Thread pool and CountDownLatch are used together in Spring project to solve the examples of statistics and accumulation business.

Business description:

To avoid disrespect, just write technology, and the business here is replaced by the analogy of "counting the total number of all kinds of animals in the zoo".

I want to write an interface and spit out "the sum of all kinds of animals in the zoo". It is known that there are 15 kinds of animals. Now there is an interface to query the number of each animal. Each animal needs to call RPC interface to query other systems. And it takes a lot of time.

Programme of work:

According to the above description, it takes a lot of time to query linearly and call the RPC interface 15 times, so the single thread mode is abandoned. The thread pool is intended to be used. After the request comes in, the thread pool will distribute 15 threads to check the data of each animal and return the result.

Specific implementation:

1. Configure thread pool

  
    <bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <! -- number of core threads -- >
    <property name="corePoolSize" value="15" />
    <! -- Maximum threads -- >
    <property name="maxPoolSize" value="30" />
    <! -- maximum queue length >= mainExecutor.maxSize  >
    <property name="queueCapacity" value="30" />
    <! -- the idle time allowed by thread pool maintenance thread is 60s by defau lt -- >
    <property name="keepAliveSeconds" value="180" />
    <! -- processing strategy of thread pool for rejected tasks (no threads available) - >
    <property name="rejectedExecutionHandler">
        <! -- callerrunspolicy: the main thread executes the task directly. After execution, it tries to add the next task to the thread pool, which can effectively reduce the speed of adding tasks to the thread pool -- >
        <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
    </property>
    </bean>

2. Specific logic in Service

    /**
     * Number of queries used by thread pool
     */
    @Autowired
    @Qualifier("threadPool")
    private ThreadPoolTaskExecutor threadPool;


  public long getAllCount(int accountType, String account) {
       try {
            // Initialization return result
            AtomicLong resultValue = new AtomicLong(0);
            // Get all animal types
            AllTypeEnum[] enumValues = AllTypeEnum.values();
            // Open the fence
            CountDownLatch countDownLatch = new CountDownLatch(enumValues .length);
            // Process each type with thread pool distribution thread allocation
            for (AllTypeEnum tempEnum : enumValues ) {
                threadPool.execute(new AnimalCountThread(account, accountType, tempEnum.getType(), resultValue, countDownLatch));
            }
            // When all threads have finished processing, return the result there
            countDownLatch.await();
            return resultValue.get();
        } catch (InterruptedException e1) { 
            log.error("Thread interrupt exception occurred", e1);
        } catch (Exception e2) { 
            log.error("Unknown exception occurred", e2);
        }
        return 0;
    }

3. Definition of thread

/**
 * Query number of animals thread
 *
 * @author XXX
 * @date 2020/05/14
 */
@Data
@Slf4j
public class AnimalCountThread implements Runnable {

    /**
     * account number
     */
    private String account;

    /**
     * Account type
     */
    private int accountType;

    /**
     * Animal type from enumeration
     */
    private int type;

    /**
     * Accumulated target value
     */
    private AtomicLong targetValue;

    /**
     * fence
     */
    private CountDownLatch countDownLatch;


    /**
     * Constructor
     *
     * @param account account number
     * @param accountType account type
     * @param type Animal type
     * @param targetValue Accumulated target value
     * @param countDownLatch fence
     */
    public AnimalCountThread (String account, int accountType, int type, AtomicLong targetValue, CountDownLatch countDownLatch) {
        this.account = account;
        this.accountType = accountType;
        this.type = type;
        this.targetValue = targetValue;
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        try {
            AllTypeEnum typeEnum = AllTypeEnum.getEnumByType(getType());
            if (typeEnum != null) {
                //Get specific business Bean
                CommonAnimalService commonAnimalService = SpringContext.getBean("commonAnimalServiceImpl");
                long num = commonAnimalService.countAnimalNum(getAccount(), getWarningType());  
                targetValue.getAndAdd(num);         
            }
        }catch (Exception e) {
            log.error("Exception in thread execution",e);
        } finally {
            countDownLatch.countDown();
        }

    }

}

 

Summary:

1. Annotations cannot be injected directly into JavaBean s in threads, so I took them from the Spring container. Or you can use anonymous inner class methods without defining this thread.

2. The cumulative target value, which can be directly used by AtomicLong, saves the synchronization by itself.

3. Use CountDownLatch and other threads to finish processing, and the main thread will take the returned results.

4. CountDownLatch in a child thread, be sure to be called to countDown(). The main thread cannot catch an exception from a child thread.

5. The thread pool is configured with a rejection policy, and the other three discard tasks, so the method given to the main thread is more suitable for the current business.

6. Configuration queue length of thread pool: cannot be too long if performance is pursued. The longer the time, the worse the interface performance.

7. The outermost layer of the interface should use the cache reasonably to relieve the pressure. The current limit can also be configured in the external RPC interface. Due to the use of multithreading, fast in and fast out, current limiting is to reduce the peak value. Fast in and fast out, even if the current limit. Throughput will also be greater than without "multithreading.".

8. Be sure to perform a pressure test. For the configuration of thread pool, you can also deploy it according to the pressure test results.

Tags: Programming Java Spring

Posted on Wed, 20 May 2020 05:32:43 -0400 by ScoTi