Tomcat的ThreadLocal

时间:2019-03-28 15:52:06

标签: java multithreading spring-boot tomcat

我有一个带有ThreadLocal变量的上下文类,我想用它来存储数据。
LDAPAttributesContextHolder

public class LDAPAttributesContextHolder {

    private static final ThreadLocal<List<Attributes>> threadLocalScope = new ThreadLocal<>();

    private LDAPAttributesContextHolder() {
        throw new IllegalStateException("ThreadLocal context class");
    }

    public static final List<Attributes> getAttributes() {
        return threadLocalScope.get();
    }

    public static final void setAttributes(List<Attributes> attributes) {
        threadLocalScope.set(attributes);
    }

    public static final void destroy() {
        threadLocalScope.remove();
    }
}

我使用此类存储用户属性,并将其用于其他服务。
Service1

@Override
    public boolean searchInLDAP(String userName, String email) {
        LOG.debug("Current thread is {}", Thread.currentThread().getName());
        LOG.debug("Start search user with login {} and email {} in LDAP directory", userName, email);
        List<Attributes> attributeList = new ArrayList<>();
        if(isEmpty(LDAPAttributesContextHolder.getAttributes())) {
            attributeList = ldapTemplate.search(query().base("ou=people").where("uid").is(userName).and("mail").is(email),
                    (AttributesMapper<Attributes>) attributes -> {
                        if(attributes == null) {
                            return null;
                        }
                        return attributes;
                    });
            LDAPAttributesContextHolder.setAttributes(attributeList);
        }
        LOG.debug("Status of searching user with login {} and email {} in LDAP is {}", userName, email, (!isEmpty(attributeList)) ? "success" : "failed");
        if(nonNull(attributeList) && !isEmpty(attributeList)) {
            logAttributes(userName);
        }
        return nonNull(attributeList) && !isEmpty(attributeList);
    }


Serivice2

public List<String> getAllFacultyGroupNamesByFacultyName() {
        String studentFacultyName = "";
        LOG.debug("Current thread is {}", Thread.currentThread().getName());
        LOG.debug("LDAPContextHolder size {}", LDAPAttributesContextHolder.getAttributes().size());
        List<Attributes> attributeList = LDAPAttributesContextHolder.getAttributes();
        LOG.debug("In method {} ,Size of attributes is  {}", Thread.currentThread().getStackTrace()[0].getMethodName(), attributeList.size());
        for(Attributes attributes : attributeList) {
            try {
                if(attributes.get(FACULTY_ATTRIBUTE) != null &&
                        attributes.get(ROLE_ATTRIBUTE) != null &&
                        !attributes.get(ROLE_ATTRIBUTE).get().toString().equals(ORGANIZATIONAL_PERSON)
                ) {
                    studentFacultyName = attributes.get(FACULTY_ATTRIBUTE).get().toString();
                    studentFacultyName = studentFacultyName.contains(IT_FACULTY.toLowerCase()) ? IT_FACULTY : studentFacultyName;
                    LOG.debug("Student faculty is {}", studentFacultyName);
                }
            } catch(NamingException e) {
                LOG.error("Error while parsing LDAP attributes. {}", e);
            }
        }

        return ...;
    }

问题在于在第一个方法线程中线程是120,但是在第二个线程中由于某种原因线程是115,而当我尝试获取上下文时,它将抛出NullPointer。
我想念什么?

1 个答案:

答案 0 :(得分:0)

df['string3']=pd.Series(['aaa','aaa','aaa','aaa'],index=[100,100,100,100]) ValueError: cannot reindex from a duplicate axis 拥有引用per thread。因此,除非每个线程对其进行初始化,否则您将获得空指针异常。从Javadoc:

  

这些变量与普通变量不同,在于每个访问一个线程(通过其ThreadLocalget方法)的线程都有其自己的,独立初始化的变量副本。

听起来像您想要单例模式。由于您使用的是Spring Boot,因此可以创建set类型的Bean,并将其自动连接到我们使用过的组件/服务中。