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