Skip to content

Commit 480cd2c

Browse files
committed
IdentityHashMap for scheduled tasks (avoiding hashCode calls on bean instances)
Issue: SPR-14666
1 parent a86f6d3 commit 480cd2c

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.Method;
2020
import java.util.Collection;
2121
import java.util.Collections;
22+
import java.util.IdentityHashMap;
2223
import java.util.LinkedHashSet;
2324
import java.util.Map;
2425
import java.util.Set;
@@ -111,7 +112,7 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
111112

112113
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
113114

114-
private final Map<Object, Set<ScheduledTask>> scheduledTasks = new ConcurrentHashMap<>(16);
115+
private final Map<Object, Set<ScheduledTask>> scheduledTasks = new IdentityHashMap<>(16);
115116

116117

117118
@Override
@@ -261,8 +262,8 @@ public Object postProcessAfterInitialization(final Object bean, String beanName)
261262
new MethodIntrospector.MetadataLookup<Set<Scheduled>>() {
262263
@Override
263264
public Set<Scheduled> inspect(Method method) {
264-
Set<Scheduled> scheduledMethods =
265-
AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
265+
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
266+
method, Scheduled.class, Schedules.class);
266267
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
267268
}
268269
});
@@ -300,11 +301,7 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
300301
String errorMessage =
301302
"Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
302303

303-
Set<ScheduledTask> tasks = this.scheduledTasks.get(bean);
304-
if (tasks == null) {
305-
tasks = new LinkedHashSet<>(4);
306-
this.scheduledTasks.put(bean, tasks);
307-
}
304+
Set<ScheduledTask> tasks = new LinkedHashSet<>(4);
308305

309306
// Determine initial delay
310307
long initialDelay = scheduled.initialDelay();
@@ -398,6 +395,16 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
398395

399396
// Check whether we had any attribute set
400397
Assert.isTrue(processedSchedule, errorMessage);
398+
399+
// Finally register the scheduled tasks
400+
synchronized (this.scheduledTasks) {
401+
Set<ScheduledTask> registeredTasks = this.scheduledTasks.get(bean);
402+
if (registeredTasks == null) {
403+
registeredTasks = new LinkedHashSet<>(4);
404+
this.scheduledTasks.put(bean, registeredTasks);
405+
}
406+
registeredTasks.addAll(tasks);
407+
}
401408
}
402409
catch (IllegalArgumentException ex) {
403410
throw new IllegalStateException(
@@ -408,7 +415,10 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
408415

409416
@Override
410417
public void postProcessBeforeDestruction(Object bean, String beanName) {
411-
Set<ScheduledTask> tasks = this.scheduledTasks.remove(bean);
418+
Set<ScheduledTask> tasks;
419+
synchronized (this.scheduledTasks) {
420+
tasks = this.scheduledTasks.remove(bean);
421+
}
412422
if (tasks != null) {
413423
for (ScheduledTask task : tasks) {
414424
task.cancel();
@@ -418,18 +428,22 @@ public void postProcessBeforeDestruction(Object bean, String beanName) {
418428

419429
@Override
420430
public boolean requiresDestruction(Object bean) {
421-
return this.scheduledTasks.containsKey(bean);
431+
synchronized (this.scheduledTasks) {
432+
return this.scheduledTasks.containsKey(bean);
433+
}
422434
}
423435

424436
@Override
425437
public void destroy() {
426-
Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
427-
for (Set<ScheduledTask> tasks : allTasks) {
428-
for (ScheduledTask task : tasks) {
429-
task.cancel();
438+
synchronized (this.scheduledTasks) {
439+
Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
440+
for (Set<ScheduledTask> tasks : allTasks) {
441+
for (ScheduledTask task : tasks) {
442+
task.cancel();
443+
}
430444
}
445+
this.scheduledTasks.clear();
431446
}
432-
this.scheduledTasks.clear();
433447
this.registrar.destroy();
434448
}
435449

0 commit comments

Comments
 (0)