简体   繁体   English

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

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

once again a question about ArrayList and synchronize.再次提出关于 ArrayList 和同步的问题。

I'd just like to know what this snippet exactly does:我只想知道这个片段到底做了什么:

ArrayList<ObjectX> list = ....;

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

Ive got a ArrayList filled with ObjectXs.我有一个装满 ObjectX 的 ArrayList。 I want to add then an element to the list, but only if the list doesnt contain the same element.我想在列表中添加一个元素,但前提是列表不包含相同的元素。 I checked before (in another method) if the list did contain the object - the result was no.我之前(以另一种方法)检查过该列表是否包含 object - 结果是否定的。 But it is possible that two threads at the same time think that the result is no and that they both try then to add objectxy.但是有可能两个线程同时认为结果是否定的,然后它们都尝试添加 objectxy。 (there are some other things which must be done inbetween, thats why I cant synchronize the whole process) (还有一些其他的事情必须在中间完成,这就是为什么我不能同步整个过程)

So, after the process and when now the threads come to the snippet above, I want to prevent that those two both add the object to the list.所以,在这个过程之后,当现在线程来到上面的代码片段时,我想防止这两个都将 object 添加到列表中。 So I thought when I synchronize access to the list, only one thread can check if it does contain the object and then add it.所以我想当我同步访问列表时,只有一个线程可以检查它是否包含 object 然后添加它。 After it, the second thread could access the list, see that the object is already in it and would not add it anymore.在它之后,第二个线程可以访问列表,看到 object 已经在其中并且不会再添加它。

Thats what I want to achieve.这就是我想要实现的。 Would it work?它会起作用吗? :-) :-)

So, if yes, Id like to know what the snippet exactly does.所以,如果是的话,我想知道这个片段到底做了什么。 Does is prevent two threads from accessing this exact code at the same time?是否会阻止两个线程同时访问此确切代码? so that the code is only available for one thread at the same time?这样代码只能同时用于一个线程

Or does it lock the list itself for the whole time, for any thread in the application who is at this moment trying to access the list - anywhere ?或者它是否一直锁定列表本身,对于此时尝试访问列表的应用程序中的任何线程 -任何地方 (I dont have other add()s in my code, but many gets(), thats why Id like to know if other threads can access the list and still get elements while another thread is accessing the code above). (我的代码中没有其他 add(),但有很多 get(),这就是为什么我想知道其他线程是否可以访问列表并在另一个线程访问上面的代码时仍然获取元素)。

The ArrayList itself is a member-variable which is connected with the principal using the application. ArrayList 本身是一个成员变量,它使用应用程序与主体连接。 It is correct that multiple various threads can access the code above at the same time if they are not sent from the same principal , correct?如果多个不同的线程不是从同一个主体发送的,那么它们可以同时访问上面的代码是正确的,对吗?

So, thats what Id like to know.所以,这就是我想知道的。 I tried to mark my questions so that its easier to answer them.我试图标记我的问题,以便更容易回答。 Thank you for helping: :-)感谢您的帮助: :-)

[EDIT] Thank you for all the answers, which almost all said the same: I think it is clear now! [编辑]谢谢你所有的答案,几乎所有人都说同样的:我想现在很清楚了! :-) :-)

  • the synchronized code block can be only accessed by one of the principals threads.同步代码块只能由主体线程之一访问。 (threads of other principals are not relevant to the speicific principal). (其他主体的线程与特定主体无关)。 the list itself can be accessed at any time from other threads - as long as the access to it is not synchronized with a synchronize-block too.列表本身可以随时从其他线程访问 - 只要对它的访问也不与同步块同步。 If it is, the thread must wait until it can access the list (that means, that no other thread is at the same time in a synchronized-block)如果是,线程必须等待,直到它可以访问列表(这意味着,没有其他线程同时在同步块中)

correct?正确的? I hope so:-)但愿如此:-)

You pretty much have it.你几乎拥有它。 The synchronized prevents other threads that lock on the same list object from running their code blocks at the same time. synchronized可防止锁定在同一list object 上的其他线程同时运行它们的代码块。 It does not lock the list object itself.它不会锁定list object 本身。 Other threads could still access it if they're not also synchronizing on the same object.如果其他线程不在同一个 object 上同步,它们仍然可以访问它。

The synchronized block guarantees that only one thread may execute this code block, or any other code block which is synchronized on the same object (ie the list) at once.同步块保证只有一个线程可以执行这个代码块,或者任何其他在同一个 object(即列表)上同步的代码块。 For example, if you have例如,如果您有

synchronized (list) {
    // block A
}

synchronized (list) {
    // block B
}

, then if one thread is executing block A, no other thread can be executing block A or block B, because they're both synchronized on the same object. ,那么如果一个线程正在执行块 A,则没有其他线程可以执行块 A 或块 B,因为它们都在同一个 object 上同步。 But the list itself isn't locked.但是列表本身并没有被锁定。 Another thread might access the list.另一个线程可能会访问该列表。

Yes, only one thread can access that code block at a time.是的,一次只有一个线程可以访问该代码块。 All other threads will wait until thread that got there first will finish execution of the code block.所有其他线程将等到最先到达那里的线程完成代码块的执行。

Also your assumption regarding user principal is correct.此外,您对用户主体的假设是正确的。 If your array list is one per user (principal), then only threads executed with that user (principal) will have to syncronize on that particular array list.如果您的数组列表是每个用户(主体)一个,那么只有使用该用户(主体)执行的线程必须在该特定数组列表上同步。

Apart from agreeing that like other answers suggested that it will ONLY block the same block of code.除了同意像其他答案一样建议它只会阻止相同的代码块。 I think the key confusion you have, and most people have is about the lock in the synchronized(lock).我认为您和大多数人遇到的关键混淆是关于同步(锁)中的锁。 You used the list itself as the lock in your case.在您的案例中,您使用列表本身作为锁。 However, using an object as an lock and if the code in the object will be blocked are totally irrelevant .但是,使用 object 作为锁和 object 中的代码是否会被阻止是完全无关的 In fact, you can use any object as the lock as long as it is the same object.实际上,只要是相同的object,您可以使用任何object作为锁。 That means if you have another member variable named foo , the code below would run essentially the same:这意味着如果您有另一个名为foo的成员变量,下面的代码将运行基本相同:

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

Every object can be used as an lock.每个 object 都可以用作锁。

It will work as long as all threads synchronize on object before doing anything.只要在做任何事情之前所有线程在 object 上同步,它就可以工作。 Common practice is hiding list form others and giving read only copy.常见的做法是向其他人隐藏列表并提供只读副本。

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)));
    }
}

Synchronization is guaranteed by encapsulation.通过封装保证同步。

Synchronized method is similar to同步方法类似于

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

And for java there is no difference on what you sychronize but it is safer to have separate lock object.对于 java,同步的内容没有区别,但使用单独的锁 object 更安全。

You could also use a Vector (a synchronized list) or other synchronized collections.您还可以使用 Vector(同步列表)或其他同步 collections。 If you are doing many reads but less writes you could use a CopyOnWriteArrayList .如果您进行多次读取但写入较少,则可以使用CopyOnWriteArrayList

But if you are often doing writes, it produces much overhead.但是,如果您经常进行写入,则会产生很多开销。

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

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