Java同步和集合 [英] Java synchronization and collections

查看:98
本文介绍了Java同步和集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果同步的代码块包含未同步的集合.集合是否被认为是线程安全的?如果没有,您能否提供两个线程可能无法安全地访问同步代码中的集合的任何实际情况?

谢谢.

解决方案

仅当访问集合的所有代码都已同步并且它们使用相同的对象"对其进行同步时.

例如,下面的代码将不会同步,因为它们已同步到不同的对象.

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,因为您认为它是以前添加的,但是这样做的线程在添加完成之前就被暂停了.

更容易想象这样的情况,例如,如果有人标记了您可以访问某个地方,那么它就会带有标志.如果标志高高,则不能进入该块.当您创建Class实例并将其绑定到该人时,总是会创建该人.因此,在下面的代码中,我们将有三个标志人".

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

synchronized语句指示标志人在有人经过它之后将其标志升起,并在其存在该块时放下它.因为我们将sync设置为class方法,所以它将绑定到该实例的标志人物".因此,不同的旗手"会举手示意某人进入处理集合的区域,但是由于他们彼此之间不同步,因此即使对方举起了旗帜,他们也会让任何人进入. >

要解决此问题,您只需要一个人即可处理这些标志.为此,您需要一个共享的标志人.在这种情况下,您可以使用集合本身.所以,你会有类似的东西

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

因为只有收藏"flag person"在升旗,所以每个人都将以谁来第一"而不是谁先完成"来访问该收藏.

我认为我的解释比应该解释的要困难一些,但我希望它可以有所帮助.如果我可以在这里画画,可能会更好地理解:P

If a synchronized block of code contains an unsynchronized collection. Is the collection considered thread safe? If not, can you provide any practical scenarios where two threads could unsafely access the collection within the synced code?

Thanks.

解决方案

Only if ALL the code that access the collection is synchronized and they use the same "object" to synchronize it.

For example, the code below would not be synchronized because they are synced to different objects.

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

Then you could have a situation that you expected a Object o to be printed because you thought that it was added before, but the thread that was doing so was halted before the add was finished.

It's easier to imagine this like if you have someone that has a flag to indicate that you can access some place. If the flag is high up, you can not enter the block. This person is always created when you create an Class instance and it's bound to it. So, in the code bellow we would have three "flag person".

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

the synchronized statement indicates the flag person to raise its flag after someone passes through it and put it down when it exists the block. Because we set the synchronized to the class method, it's bound to the "flag person" of that instance. So, diffent "flag persons" would raise their hands to someone enter the block where the collection is handled, but because they both are not synchronized to each other, they would let anyone enter, even if the other has its flags raised.

To solve this, you need only one person to handle the flags. To do this, you need a shared flag person. In this case, you could use the collection itself. So, you would have something like

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

Because only collection "flag person" is raising its flag, everyone will access the collection accordingly to "who comes first" and not "who finishes first".

I think I made my explanation a little more difficult than it should hehe but I hope it can helps. If I could draw here, it would probably be better understood :P

这篇关于Java同步和集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆