Java同步和集合(Java synchronization and collections)

2019-10-17 15:38发布

如果同步的代码块中包含非同步集合。 在收集考虑线程安全? 如果没有,你可以提供两个线程可能不安全的同步代码中访问集合任何实际的场景?

谢谢。

Answer 1:

只有当所有访问该集合的代码是同步的,它们使用相同的“对象”同步的。

例如,下面的代码将不被同步,因为它们被同步到不同的对象。

public class Foo {
    private final Collection<object> collection;

    public void Foo(Collection<object> collection) {
       this.collection = collection;
    }

    public synchronized add(Object o) {
       this.collection.add(o);
    }
}

public class Bar {
    private final Collection<object> collection;

    public void Bar(Collection<object> collection) {
       this.collection = collection;
    }

    public synchronized print() {
       for (Object o : collection) { System.out.println(o); }
    }
}

然后,你可以有你预期的情况下Object要打印O,因为你认为它是前加入,但完成添加之前停止这是这样做的线程。

它很容易想象这就像如果你有别人,有一个标志,以表明您可以访问一些地方。 如果标志是高了,你不能进入该块。 当你创建一个类实例始终创建此人,并将其绑定到它。 因此,在代码波纹管,我们将有三个“标志的人”。

...
Collection<Object> objs = new ArrayList<Object>();
Foo foo = new Foo(objs);
Bar bar = new Bar(objs);
...

synchronized语句指示标志的人有人通过它后提高其标志,并把它放下,当它存在的块。 因为我们设置同步到类方法,它绑定到该实例的“国旗人”。 所以,diffent“标志的人”会举手的人进入其中收集的处理块,但因为它们都无法同步到对方,他们会不让任何人进入,即使对方有其手举国旗。

为了解决这个问题,你只需要一个人来处理的标志。 要做到这一点,你需要一个共享标记的人。 在这种情况下,你可以使用集合本身。 所以,你会碰到这样的

public class Foo {
    private final Collection<object> collection;

    public void Foo(Collection<object> collection) {
       this.collection = collection;
    }

    public synchronized add(Object o) {
       synchronized (collection) {
           this.collection.add(o);
       }
    }
}

public class Bar {
    private final Collection<object> collection;

    public void Bar(Collection<object> collection) {
       this.collection = collection;
    }

    public print() {
       synchronized (collection) {
           for (Object o : collection) { System.out.println(o); }
       }
    }
}

因为只有集“标志的人”是提高它的标志,每个人都将相应访问集合“谁是第一位的”,而不是“谁第一个完成”。

我认为我做了我的解释有点难度比它应该呵呵,但我希望它能帮助。 如果我能在这里画,它可能会得到更好的理解:P



Answer 2:

这里是一个非常简单的对象,无界队列,我在这里另一个例子中使用:

public final class MyQueue<T> {

    private List<T> list = new ArrayList<T>();

    public T take() {
        synchronized(list) {
            while (list.size() == 0) {
                list.wait();
            }
            return list.remove(0);
        }
    }

    public void put(T object) {
        synchronized(list) {
            list.add(object);
            list.notifyAll();
        }
    }
}

这里有包封一个ArrayList,它只能访问或修改通过一个同步的方法(和所有的同步方法使用相同的锁,其被该ArrayList),所以它是线程。 这不要紧,ArrayList的方法本身并不同步。



Answer 3:

如果你能保证该集合访问一个synchronized块内,或者说在收集每次访问都是由同一对象上的synchronized块包围,那么你就应该是安全的,但往往是一个非常困难的假设证明,并可以很容易地通过,可能跟从你其他开发人员被打破。



文章来源: Java synchronization and collections