英文:
Singleton and Multithread in SpringBoot. Is it really multi thread?
问题
因为我没有明确地处理多线程,所以问题可能比较低级或者有些愚蠢,请原谅我 =)
这是我的代码调用流程:
MessageNotificationJobExecutionConfig -> AsyncMessageNotificationJobExecutor -> NotificationJobExecutor.execute()
MessageNotificationJobExecutionConfig(查找要处理的对象)在循环内调用AsyncMessageNotificationJobExecutor。
AsyncMessageNotificationJobExecutor 的 execute() 方法上有 @Async("messageNotificationTaskExecutor") 注解。
AsyncMessageNotificationJobExecutor.execute() 方法调用 NotificationJobExecutor.execute()。
messageNotificationTaskExecutor 是 ThreadPoolTaskExecutor 的一个实例。
这是我的问题:
如果我没错的话,默认情况下 NotificationJobExecutor 有一个 单例 实例。
即使 AsyncMessageNotificationJobExecutor 异步工作并使用线程池任务执行器,所有线程只调用 NotificationJobExecutor 实例(单例)。
我不确定,我可能误解了,Thread_1 调用 NotificationJobExecutor.execute(),并且在该线程完成其任务之前,其他线程会等待 Thread_1。我的推断是否正确?
我认为,即使它看起来是多线程,实际上它是单例的。
@Component("messageNotificationTaskExecutor")
public class MessageNotificationThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
// ... 省略其他代码 ...
}
@Configuration
public class MessageNotificationJobExecutionConfig {
// ... 省略其他代码 ...
}
@Service
public class AsyncMessageNotificationJobExecutor {
// ... 省略其他代码 ...
}
@Component
public class NotificationJobExecutor implements JobExecutor {
// ... 省略其他代码 ...
}
英文:
Since I am not working specifically on multi threads, the questions can be low level or even silly, please excuse me =)
Here is my code call flow like;
MessageNotificationJobExecutionConfig -> AsyncMessageNotificationJobExecutor -> NotificationJobExecutor.execute()
MessageNotificationJobExecutionConfig (finds the objects to process) and calls AsyncMessageNotificationJobExecutor inside the loop
AsyncMessageNotificationJobExecutor has @Async("messageNotificationTaskExecutor") annotation over the execute() method.
AsyncMessageNotificationJobExecutor.execute() method calls NotificationJobExecutor.execute()
messageNotificationTaskExecutor is an instance of ThreadPoolTaskExecutor
Here is my question;
If am not wrong as default NotificationJobExecutor has a singletone instance.
Even if AsyncMessageNotificationJobExecutor work async and use thread pool task executor, all thread call only NotificationJobExecutor instance (singletone).
I am not sure, I may misunderstand that Thread_1 calls NotificationJobExecutor.execute() and until this thread finish its job other thread wait for Thread_1. Is my inference correct ?
I think even if it looks multi thread actually it works singletone
@Component("messageNotificationTaskExecutor")
public class MessageNotificationThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
@Value("${message.notification.task.executor.corePoolSize}")
Integer corePoolSize;
@Value("${message.notification.task.executor.maxPoolSize}")
Integer maxPoolSize;
@Value("${message.notification.task.executor.queueCapacity}")
Integer queueCapacity;
public MessageNotificationThreadPoolTaskExecutor() {
super();
}
@PostConstruct
public void init() {
super.setCorePoolSize(corePoolSize);
super.setMaxPoolSize(maxPoolSize);
super.setQueueCapacity(queueCapacity);
}
}
@Configuration
public class MessageNotificationJobExecutionConfig {
protected Logger log = LoggerFactory.getLogger(getClass());
@Autowired
AsyncMessageNotificationJobExecutor asyncMessageNotificationJobExecutor;
@Autowired
MessageNotificationThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
JobExecutionRouter jobExecutionRouter;
@Autowired
NotificationJobService notificationJobService;
private Integer operationType = OperationType.ACCOUNT_NOTIFICATION.getValue();
@Scheduled(cron = "${message.notification.scheduler.cronexpression}")
public void executePendingJobs() {
List<NotificationJob> nextNotificationJobList = notificationJobService.findNextJobForExecution(operationType, 10);
for (NotificationJob nextNotificationJob : nextNotificationJobList) {
if (threadPoolTaskExecutor.getActiveCount() < threadPoolTaskExecutor.getMaxPoolSize()) {
asyncMessageNotificationJobExecutor.execute(nextNotificationJob);
}
}
}
}
@Service
public class AsyncMessageNotificationJobExecutor {
@Autowired
NotificationJobExecutor notificationJobExecutor;
@Autowired
NotificationJobService notificationJobService;
@Async("messageNotificationTaskExecutor")
public void execute(NotificationJob notificationJob) {
notificationJobExecutor.execute(notificationJob);
}
}
@Component
public class NotificationJobExecutor implements JobExecutor {
@Override
public Integer getOperationType() {
return OperationType.ACCOUNT_NOTIFICATION.getValue();
}
@Override
public String getOperationTypeAsString() {
return OperationType.ACCOUNT_NOTIFICATION.name();
}
@Override
public void execute(NotificationJob notificationJob) {
// TODO: 20.08.2020 will be execute
}
}
答案1
得分: 1
在您创建的场景中,您拥有所有的单例实例。但流程大致如下:
- 在
MessageNotificationJobExecutionConfig
中调用executePendingJobs
- 顺序迭代每个
NotificationJob
(因此这是等待的) - 在
AsyncMessageNotificationJobExecutor
中调用execute
,这将在messageNotificationTaskExecutor
中顺序添加一个执行(因此会阻塞)到线程池 - 在单独的线程中执行在步骤 3 中创建的作业(因此实际上会执行
AsyncMessageNotificationJobExecutor
中的方法) - 在
NotificationJobExecutor
中对execute
方法进行阻塞调用
"魔法" 发生在第 3 步,此时 Spring 不会执行方法,而是会将一个作业添加到 messageNotificationTaskExecutor
,该作业会包装对第 4 步的调用。这将导致对第 4 步的调用异步进行,因此可以同时发生对同一实例的多次调用。因此,请确保此对象是无状态的。
英文:
In the scenario you created you have all singleton instances. But the flow looks something like this:
- call to
executePendingJobs
inMessageNotificationJobExecutionConfig
- iterate over each
NotificationJob
sequentially (so this is waiting) - call to
execute
inAsyncMessageNotificationJobExecutor
which will add a execution to themessageNotificationTaskExecutor
sequential (thus blocking) to the thread pool - execute the job created in step 3 in a separate thread (so this actually executes your method in
AsyncMessageNotificationJobExecutor
- a blocking call to the
execute
method inNotificationJobExecutor
The 'magic' happens in step 3, where rather then executing the method Spring will add a job to the messageNotificationTaskExecutor
which wraps the call to step 4. This causes the call for step 4 to happen asynchronous and thus multiple calls to the same instance can occur at the same time. So make sure this object is stateless.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论