2011-08-21 48 views
2

是否可以聲明一個對象並同步,以避免兩個線程同時訪問它?或者我需要在每個對象被使用的地方聲明一個同步塊?聲明一個對象在java中同步

我試過,但無法使用synchronized這樣:

public synchronized Vector<MyObject> myvector; 

在此先感謝

回答

2

向量方法已經同步。在你的例子中,如果你只是添加/獲取/刪除對象到myVector,你不需要額外的同步。

從Java 2平臺v1.2,這個類已經更新, 實現List,使之成爲了Java的集合 框架的一部分。與新的集合實現不同,Vector是 已同步。

如果您創建一個新內部成員字段,並表示類需要同步,那麼,你需要同步進入這些領域。

1

據我所知,該關鍵字在那個地方是非法的。但是,您可以使用線程安全的對象,例如Vectors,或者可以使用synchronized(o){...}代碼塊。

方法也可能是同步的,但過於頻繁地使用它或在實際不需要同步的代碼周圍會對性能產生負面影響。

2

如果您使用的是其他集合,則集合類中的方法將同步集合。

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

這個問題有點兩方面。你想要同步什麼?訪問變量的值或訪問由變量值保存的對象的方法?

如果前者,然後the volatile keyword最接近你所需要的。它與方法/塊上的​​不完全相同,但volatile變量作用就好像它本身已同步。

如果是後者,那麼你不需要。 the legacy Vector class的方法本身已經是​​。

0

你需要通過delegatation模式同步:

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

這隻會同步當線程獲得參考 ,他們仍然可以在需要時使用該對象。

0

Vector一個同步收集,意味着它的狀態被封裝並且它的方法都是同步的。

但是,Vector雖然是線程安全的,但並不能保證你對複合動作有一致的結果(檢查項是否存在,然後執行某些操作),所以是的 - 你必須保護所有對矢量實例的訪問相同鎖(內在的或其他)。這種政策有時稱爲「客戶端鎖定」。

但即使如此,在「Vector」(迭代器使用情況等)的情況下,「完全同步」可能很難實現。

我建議,如果可以的話,切換到併發集合的更「現代」實現之一(也就是說也避免Collections.synchronizedWHATEVER)。

僅供參考 - Package java.util.concurrent

1

聲明同步字段只適用於原始類型Java中。對象不能簡單地通過聲明它們的引用同步來進行同步 - 想象如果您試圖對同一個對象進行兩次不同的引用,會發生什麼情況。

因此,你可以看到爲什麼下面的語法是不允許的:

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

public synchronized ArrayList<Object> mySyncedList = myList; 

//is the original list now synchronized or not? 

你必須這樣一些解決方案,但:

1)如果您有訪問原始的源代碼,你可以手動同步它 - 也就是說,同步所有的mutators,這樣理論上就不會出現問題。如果類很複雜,這可能會非常棘手,但至少可以保證在任何使用該類的地方,它都是同步的。

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

要小心的是:即使你自己的代碼是同步的,如果你發佈到外面那個對象的引用,那麼任何程序員那使用你的類也將不得不同步訪問該對象!