Announcement Announcement Module
Collapse
No announcement yet.
Thread-safety of calling @Bean methods from returned annonymous inner classes Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Thread-safety of calling @Bean methods from returned annonymous inner classes

    Is the following test method thread-safe, assuming that this is being called from multiple threads? Sometimes the println statement displays "null"

    Code:
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    import javax.annotation.Resource;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Scope;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.support.AnnotationConfigContextLoader;
    
    import com.oanda.bi.rm.test.AnnotationConfigTest.Config;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = { Config.class }, loader = AnnotationConfigContextLoader.class)
    public class AnnotationConfigTest {
    
        @Resource
        Map<String, Value> map;
    
        @Test
        public void test() throws InterruptedException {
            ExecutorService service = Executors.newFixedThreadPool( 10 );
    
            for ( int i = 0; i < 10; i++ ) {
                service.execute( new Runnable() {
                    @Override
                    public void run() {
                        // Is this thread-safe?
                        Value value = map.get( "value" );
    
                        // Sometimes null!
                        System.out.println( value.x );
                    }
                } );
            }
    
            service.shutdown();
            service.awaitTermination( 1, TimeUnit.MINUTES );
        }
    
        public static class Value {
            @Resource
            protected Integer x;
        }
    
        @Configuration
        public static class Config {
    
            @Bean
            public Integer x() {
                return 1;
            }
    
            @Bean
            @Scope("prototype")
            public Value value() {
                return new Value();
            }
    
            @Bean
            @SuppressWarnings("serial")
            public Map<String, Value> map() {
                // Return a Spring agnostic "bean factory" map
                return Collections.unmodifiableMap( new HashMap<String, Value>() {
                    @Override
                    public Value get( Object obj ) {
                        String key = (String) obj;
    
                        if ( key.equals( "value" ) ) {
                            // Create new bean on demand
                            return value();
                        }
    
                        // Assume other similar branches here...
    
                        return null;
                    }
                } );
            }
    
        }
    }
    Last edited by btiernay; Oct 2nd, 2012, 08:19 PM.

  • #2
    Note that if I change Collections.unmodifiableMap to Collections.synchronizedMap the problem seems to go away. This leads me to believe the decorating Spring proxy is not thread safe when used in this way. Thoughts?

    Comment


    • #3
      Created https://jira.springsource.org/browse/SPR-9852 to address this issue

      Comment

      Working...
      X