应该在Tapestry页面或组件中同步实例字段访问吗?

时间:2016-03-30 10:20:47

标签: concurrency thread-safety synchronized tapestry

如果页面或组件类具有一个非同步对象的实例字段,则为f.ex. ArrayList,如果对此字段的访问是同步的,则应用程序具有在结构上修改此字段的代码吗?

F.ex:

public class MyPageOrComponent
{
    @Persist
    private List<String> myList;

    void setupRender()
    {
        if (this.myList == null)
        {
            this.myList = new ArrayList<>();
        }
    }

    void afterRender(MarkupWriter writer)
    {
        // Should this be synchronized ?

        if (someCondition)
        {
            this.myList.add(something);
        }
        else
        {
            this.myList.remove(something);
        }
    }
}

我问,因为我似乎明白Tapestry只创建了一个页面或组件类的实例,并且它将这个实例用于所有连接的客户端(但如果不是这样,请纠正我)。

2 个答案:

答案 0 :(得分:1)

简而言之,答案是肯定的,你不必这样做,因为Tapestry会为你做这件事。 Tapestry将在运行时为您转换页面和类,这样无论您何时与字段交互,它们实际上都不会处理实例变量,而是处于线程安全的托管变量上。完整的内部工作超出了我的范围,但可以找到对转换的简要参考here

一个警告,不要在decleration处实例化您的页面/组件变量。我看到了一些奇怪的行为。所以不要这样做:

private List<String> myList = new ArrayList<String>;

答案 1 :(得分:1)

Tapestry使用一些运行时字节代码魔法来转换您的页面和组件。页面和组件是单例,但属性已转换,因此它们由PerThreadValue支持。这意味着每个请求都会获得它自己的值副本,因此不需要同步。

正如@joostschouten所建议的那样,你永远不应该在字段声明中初始化一个可变属性。他讨论的奇怪行为是因为这将由所有请求共享(因为初始化程序仅针对页面/组件单例触发一次)。应该在render方法中初始化可变字段(例如@SetupRender)