繁体   English   中英

ArrayList,线程和同步 - 同步如何准确地为多个线程工作

[英]ArrayList, Threads and synchronize - how does synchronize exactly work for multiple threads

再次提出关于 ArrayList 和同步的问题。

我只想知道这个片段到底做了什么:

ArrayList<ObjectX> list = ....;

synchronized (list) {
    if (list.contains(objectxy) == false) {
      list.add(objectxy);
    }
}

我有一个装满 ObjectX 的 ArrayList。 我想在列表中添加一个元素,但前提是列表不包含相同的元素。 我之前(以另一种方法)检查过该列表是否包含 object - 结果是否定的。 但是有可能两个线程同时认为结果是否定的,然后它们都尝试添加 objectxy。 (还有一些其他的事情必须在中间完成,这就是为什么我不能同步整个过程)

所以,在这个过程之后,当现在线程来到上面的代码片段时,我想防止这两个都将 object 添加到列表中。 所以我想当我同步访问列表时,只有一个线程可以检查它是否包含 object 然后添加它。 在它之后,第二个线程可以访问列表,看到 object 已经在其中并且不会再添加它。

这就是我想要实现的。 它会起作用吗? :-)

所以,如果是的话,我想知道这个片段到底做了什么。 是否会阻止两个线程同时访问此确切代码? 这样代码只能同时用于一个线程

或者它是否一直锁定列表本身,对于此时尝试访问列表的应用程序中的任何线程 -任何地方 (我的代码中没有其他 add(),但有很多 get(),这就是为什么我想知道其他线程是否可以访问列表并在另一个线程访问上面的代码时仍然获取元素)。

ArrayList 本身是一个成员变量,它使用应用程序与主体连接。 如果多个不同的线程不是从同一个主体发送的,那么它们可以同时访问上面的代码是正确的,对吗?

所以,这就是我想知道的。 我试图标记我的问题,以便更容易回答。 感谢您的帮助: :-)

[编辑]谢谢你所有的答案,几乎所有人都说同样的:我想现在很清楚了! :-)

  • 同步代码块只能由主体线程之一访问。 (其他主体的线程与特定主体无关)。 列表本身可以随时从其他线程访问 - 只要对它的访问也不与同步块同步。 如果是,线程必须等待,直到它可以访问列表(这意味着,没有其他线程同时在同步块中)

正确的? 但愿如此:-)

你几乎拥有它。 synchronized可防止锁定在同一list object 上的其他线程同时运行它们的代码块。 它不会锁定list object 本身。 如果其他线程不在同一个 object 上同步,它们仍然可以访问它。

同步块保证只有一个线程可以执行这个代码块,或者任何其他在同一个 object(即列表)上同步的代码块。 例如,如果您有

synchronized (list) {
    // block A
}

synchronized (list) {
    // block B
}

,那么如果一个线程正在执行块 A,则没有其他线程可以执行块 A 或块 B,因为它们都在同一个 object 上同步。 但是列表本身并没有被锁定。 另一个线程可能会访问该列表。

是的,一次只有一个线程可以访问该代码块。 所有其他线程将等到最先到达那里的线程完成代码块的执行。

此外,您对用户主体的假设是正确的。 如果您的数组列表是每个用户(主体)一个,那么只有使用该用户(主体)执行的线程必须在该特定数组列表上同步。

除了同意像其他答案一样建议它只会阻止相同的代码块。 我认为您和大多数人遇到的关键混淆是关于同步(锁)中的锁。 在您的案例中,您使用列表本身作为锁。 但是,使用 object 作为锁和 object 中的代码是否会被阻止是完全无关的 实际上,只要是相同的object,您可以使用任何object作为锁。 这意味着如果您有另一个名为foo的成员变量,下面的代码将运行基本相同:

synchronized (foo) {
    if (list.contains(objectxy) == false) {
      list.add(objectxy);
    }
}

每个 object 都可以用作锁。

只要在做任何事情之前所有线程在 object 上同步,它就可以工作。 常见的做法是向其他人隐藏列表并提供只读副本。

public class ThreadSafeList {

    private ArrayList<String> list = new ArrayList<String>();


    public synchronized void addUnique(String s) {
        if (!list.contains(s)) {
            list.add(s);
        }
    }


    public synchronized List<String> getList() {
         return Collections.unmodifiableList((new ArrayList<String>(list)));
    }
}

通过封装保证同步。

同步方法类似于

  public void addUnique(String s) 
   synchronized(this){
   list.add(s);
  }

对于 java,同步的内容没有区别,但使用单独的锁 object 更安全。

您还可以使用 Vector(同步列表)或其他同步 collections。 如果您进行多次读取但写入较少,则可以使用CopyOnWriteArrayList

但是,如果您经常进行写入,则会产生很多开销。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM