如何在java中组合线程和threadlocal

时间:2013-06-06 03:18:03

标签: java

我有一些声明如下的方法:

声明此类使用ThreadLocal从容器中获取Service组件。

public class ThreadContext {
    private Connector connector;
    private static ThreadLocal threadLocal = new ThreadLocal() {        
        @Override
        protected Connector initialValue() {
            Service service =  
                   (Service) Container.getComponentInstanceOfType(Service.class);
            Connector connector = service.getConnector();  
            return connector;
        }
    };

    public static Connector get() {
        return Connector threadLocal.get();
    }
}

Connector是中产阶级

public class Connector {
    public Collection<Result> search() {
        User user = ConversationUser.getCurrent()
    }
}

宣布ConversationUser也使用ThreadLocal

public class ConversationUser {
    private static ThreadLocal<ConversationUser> current = 
                                            new ThreadLocal<ConversationUser>();

    public static ConversationUser getCurrent() {
        return current.get();//(1)
    }
}

然后,我写了一个线程来执行以下操作:

Thread thread = null;
thread = new Thread(new Runnable() {
    public void run(){
        ThreadContext context = new ThreadContext();          
        Collection<Result> result = context.get().search();//(2)
        resultsTemp.put("File", result);
    }
});          
thread.start();

此线程正常工作但在第(2)行发生NullPointerException。 正如我调查的那样,方法在第(1)行返回null。

我真的很困惑。我不明白为什么会出现问题。请给我一些澄清,谢谢。

2 个答案:

答案 0 :(得分:4)

您正在初始化ConversationUser.currentnew ThreadLocal<ConversationUser>(),而不是匿名扩展以覆盖initialValue(),就像您对ThreadContext.threadLocal所做的那样。因此,在首次调用get时,没有什么可以告诉它如何填充自己。由于没有代码调用set来手动填充,get会返回null

有关更多信息和有用的示例,请参阅ThreadLocal javadoc。

答案 1 :(得分:0)

我做了一些测试,问题是因为私有静态ThreadLocal变量,我不知道为什么但这不是将对象链接到ThreadLocal,似乎对象不存在创建。我需要更多时间来调查它。

无论如何,我看到两种解决方案可以解决这个问题:

  1. 将此类创建为Singleton

    public class ConversationUser extends ThreadLocal<ConversationUser>{
        private static ThreadLocal<ConversationUser> current= null;
    
    @Override
        protected ConversationUser initialValue() {
            return new ConversationUser();
        }
    
        public static ConversationUser getCurrent() {
            if (current == null) {
                current = new ConversationUser();
            }
            return current.get();
        }
    
        }
    

    // usage ConversationUser.getCurrent()

  2. 忘掉这个静态变量并始终通过创建ThreadLocal对象的新实例来访问它

    public class ConversationUser extends ThreadLocal<ConversationUser>{
    
    @Override
        protected ConversationUser initialValue() {
            return new ConversationUser();
        }
    
        }
    

    // usage new ConversationUser().get();