java 是否与ThreadLocal和InheritableThreadLocal同步?

2jcobegt  于 2023-05-12  发布在  Java
关注(0)|答案(1)|浏览(99)

我正在实现一个遵循这个thread local pattern的vaadin应用程序。
应用程序的状态由多个工作线程修改。因此,为了通知应用程序其状态已更改,我添加了一个进度指示器。
阅读进度指示器示例,我看到了以下内容:

// All modifications to Vaadin components should be synchronized
        // over application instance. For normal requests this is done
        // by the servlet. Here we are changing the application state
        // via a separate thread.
        synchronized (getApplication()) {
            prosessed();
        }

所以基本上,我认为我只需要修改对getApplication的调用来获取我的应用程序的示例(只需调用getCurrent):

private static ThreadLocal<MyApplication> currentApplication = new ThreadLocal<MyApplication>();

    @Override
    public void init() {
        setCurrent(this); // So that we immediately have access to the current application

        // initialize mainWindow and other stuff

        // Register a transaction listener that updates our ThreadLocal with each request
        if (getContext() != null) {
            getContext().addTransactionListener(this);
        }   
    }

    /**
     * @return the current application instance
     */
    public static MyApplication getCurrent() {
        return currentApplication.get();
    }

问题是我的工作线程死于饥饿,因为它无法获得应用程序上的互斥体。vaadin论坛提供的一个解决方案是使用InheritableThreadLocal。它工作,但我不明白为什么。
在javadoc中:
这个类扩展了ThreadLocal以提供从父线程到子线程的值继承:当创建子线程时,子线程接收父线程具有值的所有可继承线程局部变量的初始值。通常,子节点的值与父节点的值相同;但是,通过重写该类中的childValue方法,可以使子对象的值成为父对象的任意函数。
当在变量中维护的每线程属性(例如,用户ID、事务ID)必须被自动传输到所创建的任何子线程时,优先于普通线程局部变量使用可继承线程局部变量。
我的辅助线程无法获得锁,因为它没有接收初始值?我是不是误解了什么?除了this problem,我应该注意使用InheritableThreadLocal的潜在陷阱是什么?
谢谢

5gfr0r5j

5gfr0r5j1#

理解它如何工作的关键是ThreadLocal类中的方法:

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
   return new ThreadLocalMap(parentMap);
}

它被设计为只能从Thread构造函数调用。该方法

protected Object childValue(Object parentValue)

用于将子线程中的InheritableThreadLocal变量的初始值设置为父线程中的ThreadLocal变量(作为参数传递)的函数。这个方法在创建子线程之前从父线程中调用,默认实现将使子线程的值与父线程的值相同,但是我们可以重写childValue()方法,将子线程的值设置为父线程中具有值的ThreadLocals的父线程值的函数。默认情况下,childValue()返回相同的输入参数,但是childValue()方法的重写也可能会更改此行为。
因此,InheritableThreadLocal的工作方式几乎与ThreadLocal相似,并且具有相同的同步缺陷。

相关问题