ThreadLocal供应商?

时间:2015-07-21 18:41:43

标签: java java-8

如果我需要一个变量的ThreadLocal,是否还需要使用Supplier(也是线程安全的)?

例如,供应商不需要在这里完成线程安全吗?

private ThreadLocal<Supplier<MyClass>> myObject = new ThreadLocal<Supplier<MyClass>>();

感谢。

3 个答案:

答案 0 :(得分:12)

您的问题没有显示将供应商与ThreadLocal一起使用的典型方法。如果你想要一个MyClass的ThreadLocal,那么旧的(1.8之前的)方法通常是:

ThreadLocal<MyClass> local = new ThreadLocal<MyClass>();

// later
if (local.get() == null) {
  local.put(new MyClass());
}
MyClass myClass = local.get();

另一种方法是delcare ThreadLocal的子类,它覆盖了initialValue方法。

在1.8中,您可以使用供应商来处理初始化:

ThreadLocal<MyClass> local = ThreadLocal.withInitial(() -> new MyClass());

从功能上讲,这两者基本相同,但供应商版本的代码要少得多。

答案 1 :(得分:3)

这取决于如何返回Supplier类。

在这些情况下需要同步:

  • 让我们说它在每次创建之间保持某种状态,它需要是线程安全的。即需要在Supplier.get()方法上进行同步。
  • 如果从缓存中提取返回的对象。

在这些情况下无需同步:

  • 如果是更简单的工厂,总是创建并返回对象。

在这两种情况下, MyClass无需同步。因为它始终是本地的线程。

答案 2 :(得分:0)

希望我能帮上忙。我想我可以解释两个问题:一个是threadlocal解决“线程安全”问题吗?另一个是供应商提供的功能。

要回答第一个问题: 实际上,threadlocal不能保证“线程安全”。 Threadlocal仅使线程可以访问其自己的threadlocal值副本。通常,它用于维护在同一线程中调用的几种方法中使用的上下文消息。

要回答第二个问题: 简而言之,使用“ ThreadLocal.withInitial(()-> new MyClass())”创建ThreadLocal的实例,每次在新线程中首次调用threadlocal变量的get()方法时,您将获得供应商创建的值函数“()-> new MyClass()”。

更多详细信息: 实际上,此“ withInitial”方法返回一个扩展了ThreadLocal的SuppliedThreadLocal实例。

这是SuppliedThreadLocal的源代码:

static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {

    private final Supplier<? extends T> supplier;

    SuppliedThreadLocal(Supplier<? extends T> supplier) {
        this.supplier = Objects.requireNonNull(supplier);
    }

    @Override
    protected T initialValue() {
        return supplier.get();
    }
}

我们可以看到它覆盖了initialValue方法,以返回供应商创建的变量。

在哪里使用了“ initialValue()”方法?

在Threadlocal实例的get()方法中,将调用setInitialValue,并在此处调用initialValue()。

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}

这意味着当当前线程不在此线程局部变量的当前线程副本中保存值时,将在此处调用供应商函数以创建新变量。

希望这会有所帮助。