Skip to content

Commit bd24b97

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

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;
@@ -113,7 +114,7 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
113114
Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>(64));
114115

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

118119

119120
@Override
@@ -263,8 +264,8 @@ public Object postProcessAfterInitialization(final Object bean, String beanName)
263264
new MethodIntrospector.MetadataLookup<Set<Scheduled>>() {
264265
@Override
265266
public Set<Scheduled> inspect(Method method) {
266-
Set<Scheduled> scheduledMethods =
267-
AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
267+
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
268+
method, Scheduled.class, Schedules.class);
268269
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
269270
}
270271
});
@@ -302,11 +303,7 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
302303
String errorMessage =
303304
"Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
304305

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

311308
// Determine initial delay
312309
long initialDelay = scheduled.initialDelay();
@@ -400,6 +397,16 @@ protected void processScheduled(Scheduled scheduled, Method method, Object bean)
400397

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

411418
@Override
412419
public void postProcessBeforeDestruction(Object bean, String beanName) {
413-
Set<ScheduledTask> tasks = this.scheduledTasks.remove(bean);
420+
Set<ScheduledTask> tasks;
421+
synchronized (this.scheduledTasks) {
422+
tasks = this.scheduledTasks.remove(bean);
423+
}
414424
if (tasks != null) {
415425
for (ScheduledTask task : tasks) {
416426
task.cancel();
@@ -420,18 +430,22 @@ public void postProcessBeforeDestruction(Object bean, String beanName) {
420430

421431
@Override
422432
public boolean requiresDestruction(Object bean) {
423-
return this.scheduledTasks.containsKey(bean);
433+
synchronized (this.scheduledTasks) {
434+
return this.scheduledTasks.containsKey(bean);
435+
}
424436
}
425437

426438
@Override
427439
public void destroy() {
428-
Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
429-
for (Set<ScheduledTask> tasks : allTasks) {
430-
for (ScheduledTask task : tasks) {
431-
task.cancel();
440+
synchronized (this.scheduledTasks) {
441+
Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
442+
for (Set<ScheduledTask> tasks : allTasks) {
443+
for (ScheduledTask task : tasks) {
444+
task.cancel();
445+
}
432446
}
447+
this.scheduledTasks.clear();
433448
}
434-
this.scheduledTasks.clear();
435449
this.registrar.destroy();
436450
}
437451

0 commit comments

Comments
 (0)