Timed task, thread pool, lock

Posted by scarface222 on Wed, 29 Dec 2021 11:16:51 +0100

Project: springBoot, jdk1 8. mysql database

Concept: the principle and configuration of thread pool class and the related principles of ReentrantLock class have been explained by many professionals on the Internet, and they are very complete. I won't describe them here

Objective: to configure thread pool, timing tasks, multithreading tasks, thread lock

1. Configure the thread pool and create a new ExecutorConfig class

@EnableAsync
@Configuration
public class ExecutorConfig {

    @Bean("executorReal")
    public TaskExecutor executorReal(){

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("my-task-");//Custom thread name
        executor.setMaxPoolSize(256);//Maximum number of threads
        executor.setCorePoolSize(32);//Number of cores
        executor.setQueueCapacity(1024);//Number of queue threads
        executor.setKeepAliveSeconds(60);//waiting time
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        return executor;
    }

}
//Add timed task annotation on startup class
@EnableScheduling//Timed task annotation @MapperScan("com.dao.*") @SpringBootApplication public class ZyApplication { public static void main(String[] args){ SpringApplication.run(ZyApplication.class); } }

2. Scheduled task class

Write two methods, let them call the same method at the same time, and let them compete

ReentrantLock is a thread lock that locks the current method. Only one thread is allowed to access it. After the lock is released, other threads can access it
ReentrantLock.tryLock(long time,TimeUnit unit) method is used to obtain the lock
If the current method is not locked by the thread, it returns true. After the method is executed, it will lock the current thread, and the acquisition of other threads will become false, so as to control the locking and access order

The meaning of the parameter is that long time represents data, TimeUnit unit represents unit, and timeunit Seconds is seconds, timeunit Minutes is a minute English translation is very clear

tryLock(5,TimeUnit.SECONDS) indicates the time for obtaining the lock for 5 seconds. If the lock is not obtained within this time, the lock will be obtained all the time. After this time, the lock acquisition will be abandoned

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: Poison Night Charm
 * @time: 2021-12-27 14:08
 * @description:
 */
@EnableAsync
@Component
public class MyTask {

    private static final Logger log = LoggerFactory.getLogger(MyTask.class);

    private static ReentrantLock lock = new ReentrantLock(true);

    @Autowired
    private TaskService taskService;

    @Async("executorReal")
    @Scheduled(cron = "0 0/2 * * * ?")//Every two minutes
    public void task1() throws InterruptedException {

        log.info(GetGeneralUtils.getUuid()+"   task1  order exe....");

        if(lock.tryLock(5, TimeUnit.SECONDS)){
            try{
                log.info("task1 lock.........");
                taskService.task1();
            }finally {
                lock.unlock();
                log.info("task1 unlock.........");
            }
        }else{
            log.info("task1 lock failed.........");
        }

    }

    @Async("executorReal")
    @Scheduled(cron = "0 0/2 * * * ?")//Every two minutes
    public void task11() throws InterruptedException {

        log.info(GetGeneralUtils.getUuid()+"   task11  order exe....");
        if(lock.tryLock(5, TimeUnit.SECONDS)){
            try{
                log.info("task11 lock .........");
                taskService.task1();
            }finally {
                lock.unlock();
                log.info("task11 unlock .........");
            }
        }else{
            log.info("task11 lock failed .........");
        }
    }

}

 

3. service class method. Here I write a test method

Because a piece of data is updated quickly, it is specially dormant for 4 seconds to reflect the role of tryLock(5,TimeUnit.SECONDS)

 

4. Start the project and view the scheduled task execution log

2021-12-29 15:16:00.008 [my-task-2] INFO  com.my.demo.task.MyTask - a3604752-308d-4852-8748-2b95290d4167   task11  order exe....
2021-12-29 15:16:00.008 [my-task-1] INFO  com.my.demo.task.MyTask - d9199bda-7d5a-462f-a4e8-6c049d56e7dc   task1  order exe....
2021-12-29 15:16:00.008 [my-task-1] INFO  com.my.demo.task.MyTask - task1 lock.........
2021-12-29 15:16:00.027 [my-task-1] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
2021-12-29 15:16:00.148 [my-task-1] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
2021-12-29 15:16:00.152 [my-task-1] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - ==>  Preparing: UPDATE t_test SET id = id,customer_id = ?,customer_name = ?,add_account_id = ?,add_time = ?,update_account_id = ?,update_time = ? WHERE id = ? 
2021-12-29 15:16:00.164 [my-task-1] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - ==> Parameters: 1(Integer), Test 1(String), 0(Integer), 2021-12-29 15:16:00.016(Timestamp), 0(Integer), 2021-12-29 15:16:00.016(Timestamp), 1(Integer)
2021-12-29 15:16:00.204 [my-task-1] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - <==    Updates: 1
2021-12-29 15:16:04.206 [my-task-1] INFO  com.my.demo.task.MyTask - task1 unlock.........
2021-12-29 15:16:04.206 [my-task-2] INFO  com.my.demo.task.MyTask - task11 lock .........
2021-12-29 15:16:04.208 [my-task-2] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - ==>  Preparing: UPDATE t_test SET id = id,customer_id = ?,customer_name = ?,add_account_id = ?,add_time = ?,update_account_id = ?,update_time = ? WHERE id = ? 
2021-12-29 15:16:04.209 [my-task-2] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - ==> Parameters: 1(Integer), Test 1(String), 0(Integer), 2021-12-29 15:16:04.206(Timestamp), 0(Integer), 2021-12-29 15:16:04.206(Timestamp), 1(Integer)
2021-12-29 15:16:04.254 [my-task-2] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - <==    Updates: 1
2021-12-29 15:16:08.255 [my-task-2] INFO  com.my.demo.task.MyTask - task11 unlock .........

As can be seen from the above, both methods are started and two threads are enabled

Although thread 2 executes first, thread 1 grabs the lock at 15:16:00.008, and then the sql update execution is completed until 15:16:04.206 releases the lock

At this time, because thread 2 has been waiting, the lock is set for 5 seconds. When thread 1 releases the lock at {15:16:04.206}, it immediately takes the lock within the effective time, and then the execution is completed. The lock is released at {15:16:08.255}

 

5. Lock execution will be abandoned when the lock acquisition time is exceeded

The scheduled tasks remain unchanged. Extend the sleep time of task1 method in service class to 6 seconds

 

 

View execution log

2021-12-29 16:18:00.008 [my-task-2] INFO  com.my.demo.task.MyTask - e7819e1e-32c4-4389-928a-6877f62bac8f   task1  order exe....
2021-12-29 16:18:00.008 [my-task-1] INFO  com.my.demo.task.MyTask - c45f0ce3-720d-41ce-b3da-1f6cdc703868   task11  order exe....
2021-12-29 16:18:00.008 [my-task-2] INFO  com.my.demo.task.MyTask - task1 lock.........
2021-12-29 16:18:00.028 [my-task-2] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
2021-12-29 16:18:00.153 [my-task-2] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
2021-12-29 16:18:00.157 [my-task-2] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - ==>  Preparing: UPDATE t_test SET id = id,customer_id = ?,customer_name = ?,add_account_id = ?,add_time = ?,update_account_id = ?,update_time = ? WHERE id = ? 
2021-12-29 16:18:00.170 [my-task-2] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - ==> Parameters: 1(Integer), Test 1(String), 0(Integer), 2021-12-29 16:18:00.016(Timestamp), 0(Integer), 2021-12-29 16:18:00.016(Timestamp), 1(Integer)
2021-12-29 16:18:00.233 [my-task-2] DEBUG com.my.demo.dao.test.TestMapper.updateByPrimaryKey - <==    Updates: 1
2021-12-29 16:18:05.008 [my-task-1] INFO  com.my.demo.task.MyTask - task11 lock failed .........
2021-12-29 16:18:06.234 [my-task-2] INFO  com.my.demo.task.MyTask - task1 unlock.........

16: 18:00.008 two threads execute at the same time. Thread 2 grabs the lock first and then executes the task

At this time, thread 1 has been waiting for the release of the lock. At 16:18:05:008, the set effective time has expired and the acquisition is directly abandoned

16: At 18:06.234, thread 2 finished releasing the lock