在java中将对象声明为synchronized

时间:2011-08-21 04:49:26

标签: java multithreading thread-safety

是否可以声明一个对象并同步避免两个线程同时访问它?或者我需要在使用对象的每个点声明一个同步块?

我试过但不可能以这种方式使用同步:

    public synchronized Vector<MyObject> myvector;

提前致谢

7 个答案:

答案 0 :(得分:2)

矢量方法已经同步。在您的示例中,如果您只是向myVector添加/获取/删除对象,则不需要其他同步。

  

从Java 2平台v1.2开始,此类已经过改进   实现List,使它成为Java集合的一部分   框架。与新的集合实现不同,Vector是   同步。

如果使用内部成员字段创建 new 类,并且所述类需要同步,则是,您需要同步对这些字段的访问。

答案 1 :(得分:2)

如果您正在使用其他一些集合,则Collections类中有一些方法可以同步集合。

List<MyObject> myList = Collections.synchronizedList( new ArrayList<MyObject> );

答案 2 :(得分:1)

据我所知,关键字在那个地方是非法的。但是,您可以使用线程安全的对象,例如Vectors,或者您可以使用synchronized(o){...}代码块。

方法也可以同步,但过于频繁地使用或者使用真正不需要同步的代码会对性能产生负面影响。

答案 3 :(得分:0)

这个问题有点双重。你想要同步到底是什么?是否可以访问变量的值或访问由变量值保存的对象的方法?

如果是前者,那么the volatile keyword最接近你所需要的。它与方法/块上的synchronized不完全相同,但volatile变量的行为就像它自身同步一样。

如果是后者,那么你不需要。 the legacy Vector class的方法本身已经synchronized

答案 4 :(得分:0)

您需要通过委托模式进行同步:

private volatile Vector<MyObject> myObjects;

public synchronized boolean addMyObject(MyObject o) {
    return myObjects.add(o);
}

// etc for other methods of Vector that you want to expose.

请注意,同步访问器方法不会这样做:

private volatile Vector<MyObject> myObjects;

public synchronized Vector<MyObject> getMyObjects() {
    return myObjects;
}

只有在线程获得引用时才会同步,他们仍然可以在需要时使用该对象。

答案 5 :(得分:0)

Vector 同步集合,意味着其状态已封装且其方法全部同步。

但是,Vector虽然是线程安全的,但并不能保证你在复合操作上获得一致的结果(检查项目是否存在然后做某事),所以是的 - 你必须保护对向量的所有访问权限具有相同锁定的实例(内在或其他)。这种策略有时被称为“客户端锁定”。

但即便如此,在Vector(迭代器使用等)的情况下,“完全同步”可能很难实现。

如果可以的话,我建议切换到一个更“现代”的并发集合实现(这也意味着避免Collections.synchronizedWHATEVER)。

供参考 - Package java.util.concurrent

答案 6 :(得分:0)

声明同步字段仅适用于Java中的基元类型。仅通过声明其引用是同步的,无法同步对象 - 想象如果您尝试对同一个对象进行两次不同的引用会发生什么。

因此,您可以看到为什么不允许使用以下语法:

public ArrayList<Object> myList = new ArrayList<Object>();

public synchronized ArrayList<Object> mySyncedList = myList; 

//is the original list now synchronized or not?

你确实有一些解决方案:

1)如果您可以访问原始源代码,则可以手动同步它 - 即同步所有变更器,以便理论上不会出现任何问题。如果类很复杂,这可能会很棘手,但至少可以保证在使用该类的任何位置时,它都是同步的。

public class MyCollection {
    public synchronized void addObject(Object a) {
        ...
    }
}

特别是,Vector类是内部同步的,在您的示例中,不需要对其进行更多同步。但是,您自己的类和许多Java类都没有这种保证。

2)如果Object是Java库类,则可能有一种方法可以使用库功能获取同步副本。这通常用于列表:

public List<Object> mySyncedList = Collections.synchronizedList(myList);

//pass around mySyncedList instead of myList to guarantee synchronization

3)如果对象没有内部同步,并且没有提供获取它的同步副本的方法,并且您无法编辑原始源代码,则别无选择,只能同步代码修改对象:

synchronized(myList) {
    myList.add(next);
}

请注意:即使您自己的代码是同步的,如果您将该Object的引用发布到外部,那么使用您的类的任何程序员也必须同步对该Object的访问!