【问题标题】:Synchronized Non-Final List [duplicate]同步的非最终名单[重复]
【发布时间】:2023-04-10 16:47:01
【问题描述】:

好的,据我了解,最好创建一个final static 用于同步的对象。

但是,我也读到如果对象引用没有改变,那么它不会有并发问题。

以下代码是否违反同步性?

class Foo {
    private static ArrayList<Client> clients = null;

    public Foo() {
        clients = new ArrayList<>();
        //add stuff to list here..
    }

    public void addClient(Client C) {
        synchronized(clients) {
            clients.add(C);
        }
    }
}

如果客户ArrayList 从未直接公开(仅通过Getters 除外),我是否必须使客户成为最终对象或创建最终对象?换句话说,我从不为 clients 数组提供 set 方法,因此引用永远不会改变。

【问题讨论】:

  • 如果引用没有改变,那为什么不把它定下来呢?
  • 我在这里没有看到任何问题,但为什么不把它定下来呢?
  • 我在想 C++ 中的 final = const,所以如果我这样做了,我就无法添加任何东西。但谷歌搜索后,我发现它不一样。
  • 我看不出有什么理由在这里使用 static,如上所述,你最好使用 final

标签: java synchronized


【解决方案1】:

任何创建 Foo new Foo() 实例的人都会覆盖客户端数组。它绝对不是线程安全的

【讨论】:

  • 如何 :S 它是一个静态数组..
  • 静态不代表不能赋值。你想要的是它是最终的。但是如果你把它设为 static final 则上面的代码将无法编译,因为你不能对同一个成员进行 2 次赋值(第一个 null 比实际数组)
【解决方案2】:

如果您真的希望客户端是静态的,即所有 Foo 共享一个客户端列表,以便收集所有客户端的巨大列表,那么您只需初始化一次。

private static ArrayList<Client> clients = new ArrayList();

但我怀疑您希望每个 Foo 有一个客户列表,在这种情况下,不要将其声明为静态,为清楚起见,将其声明为最终的。 (还有一些奇怪的极端情况,您必须将其声明为 final,如 Java 并发实践中所述。)

【讨论】:

  • 是的 :) 我想要一个包含所有 Foos 的列表,所以我将其设为静态。我像你一样初始化它并使它成为最终的。我不确定,因为在 C++ 中,我只能在构造函数或初始化列表中初始化。还在学习java。这是一个简洁的功能。谢谢!
【解决方案3】:

为了使其线程安全,像这样更改“客户”的声明:

private final static List<Client> clients = new ArrayList<Client>();

并像以前一样使用“同步”。

如果您对 static 关键字的含义感到困惑: static 关键字意味着 'clients' 的同一个实例将被 Foo 的所有实例共享。如果你删除 static 关键字,每个 Foo 实例都会有它自己的 'clients' 实例。

final 关键字只是阻止您重新分配 clients 变量。

【讨论】:

    猜你喜欢
    • 2013-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 1970-01-01
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多