From bd24b97bd3df75e811c7b2ca07e65c6bfb8c90d6 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 13 Sep 2016 21:44:29 +0200 Subject: [PATCH] IdentityHashMap for scheduled tasks (avoiding hashCode calls on bean instances) Issue: SPR-14666 (cherry picked from commit 480cd2c) --- .../ScheduledAnnotationBeanPostProcessor.java | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java index 89d35299a05..7b5cb34f6f0 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java @@ -19,6 +19,7 @@ package org.springframework.scheduling.annotation; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; +import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -113,7 +114,7 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea Collections.newSetFromMap(new ConcurrentHashMap, Boolean>(64)); private final Map> scheduledTasks = - new ConcurrentHashMap>(16); + new IdentityHashMap>(16); @Override @@ -263,8 +264,8 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea new MethodIntrospector.MetadataLookup>() { @Override public Set inspect(Method method) { - Set scheduledMethods = - AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class); + Set scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations( + method, Scheduled.class, Schedules.class); return (!scheduledMethods.isEmpty() ? scheduledMethods : null); } }); @@ -302,11 +303,7 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required"; - Set tasks = this.scheduledTasks.get(bean); - if (tasks == null) { - tasks = new LinkedHashSet(4); - this.scheduledTasks.put(bean, tasks); - } + Set tasks = new LinkedHashSet(4); // Determine initial delay long initialDelay = scheduled.initialDelay(); @@ -400,6 +397,16 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea // Check whether we had any attribute set Assert.isTrue(processedSchedule, errorMessage); + + // Finally register the scheduled tasks + synchronized (this.scheduledTasks) { + Set registeredTasks = this.scheduledTasks.get(bean); + if (registeredTasks == null) { + registeredTasks = new LinkedHashSet(4); + this.scheduledTasks.put(bean, registeredTasks); + } + registeredTasks.addAll(tasks); + } } catch (IllegalArgumentException ex) { throw new IllegalStateException( @@ -410,7 +417,10 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea @Override public void postProcessBeforeDestruction(Object bean, String beanName) { - Set tasks = this.scheduledTasks.remove(bean); + Set tasks; + synchronized (this.scheduledTasks) { + tasks = this.scheduledTasks.remove(bean); + } if (tasks != null) { for (ScheduledTask task : tasks) { task.cancel(); @@ -420,18 +430,22 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea @Override public boolean requiresDestruction(Object bean) { - return this.scheduledTasks.containsKey(bean); + synchronized (this.scheduledTasks) { + return this.scheduledTasks.containsKey(bean); + } } @Override public void destroy() { - Collection> allTasks = this.scheduledTasks.values(); - for (Set tasks : allTasks) { - for (ScheduledTask task : tasks) { - task.cancel(); + synchronized (this.scheduledTasks) { + Collection> allTasks = this.scheduledTasks.values(); + for (Set tasks : allTasks) { + for (ScheduledTask task : tasks) { + task.cancel(); + } } + this.scheduledTasks.clear(); } - this.scheduledTasks.clear(); this.registrar.destroy(); }