java 對象 線程安全_JAVA并發編程學習:構造線程安全的對象

 2023-10-08 阅读 21 评论 0

摘要:設計線程安全的類實例限制當一個對象被另一個對象封裝時,所有訪問被被封裝對象的代碼路徑就是全部可知的,這相比于讓對象可被整個系統訪問來說,更容易對代碼路徑進行分析。將數據封裝在對象內部,把對數據的訪問限制在對象的方法上,更易確保

設計線程安全的類

實例限制

當一個對象被另一個對象封裝時,所有訪問被被封裝對象的代碼路徑就是全部可知的,這相比于讓對象可被整個系統訪問來說,更容易對代碼路徑進行分析。將數據封裝在對象內部,把對數據的訪問限制在對象的方法上,更易確保線程在訪問數據時總能獲得正確的鎖

被限制對象一定不能溢出到它的期望可用的范圍之外。可以把對象限制在本地變量、類的實例(比如私有類的成員)或線程(比如對象在線程內部從一個方法傳遞到另一個方法,不過前提是該對象不被跨線程共享),下面的例子未對Person的線程安全性作任何假設,但如果它是可變的,那么可能還需要額外同步

@ThreadSage

public class PersonSet

{

@GuardedBy("this")

private final Set mySet=new HashSet();

public synchronized void addPerson(Person p)

{

mySet.add(p);

}

public synchronized boolean containsPerson(Person p)

{

return mySet.contains(p);

}

}

監視器

使用私有鎖對象,而不是對象的內部鎖(或任何其他可公共訪問的鎖)

public class PrivateLock

{

private final Object myLock=new Object();

@GuardedBy("myLock") Widget widget;

void somenMethod()

{

synchronized(myLock)

{

//訪問或修改widget的狀態

}

}

}

范例:機動車追蹤器

package com.henrysun.javaSE.bfbc;

import java.util.Collections;

import java.util.HashMap;

import java.util.Map;

import org.apache.http.annotation.GuardedBy;

/**

* 線程安全類,JAVA監視器模式

* 范例:機動車追蹤器

* 一個用于調度出租車,警車,貨運卡車等機動車的“機動車追蹤器”,每一輛機動車都有一個String標識

* 并有一個與之對應的位置(X,Y),視圖線程和多個更新線程會并發的訪問數據模型

* @author Sam Flynn

*

*/

public class MonitorVehicleTracker {

@GuardedBy("this")

private final Map locations;

public MonitorVehicleTracker(Map locations)

{

this.locations=deepCopy(locations);

}

public synchronized Map getLocations() {

return deepCopy(locations);

}

public synchronized MutablePoint getLocation(String id) {

MutablePoint loc=locations.get(id);

return loc==null?null:new MutablePoint(loc);

}

public synchronized void setLocation(String id,int x,int y)

{

MutablePoint loc=locations.get(id);

if(loc==null)

{

throw new IllegalArgumentException("No such ID:"+id);

}

loc.x=x;

loc.y=y;

}

private static Map deepCopy(Map m)

{

Map result=new HashMap();

for(String id:m.keySet())

{

result.put(id, new MutablePoint(m.get(id)));

}

return Collections.unmodifiableMap(result);

}

}

/**

* 可變point

* @author Sam Flynn

*

*/

class MutablePoint

{

public int x,y;

public MutablePoint(){x=0;y=0;}

public MutablePoint(MutablePoint p)

{

this.x=p.x;

this.y=p.y;

}

}

先復制可變的數據,再返回給用戶,這種實現方式只能簡單的維護線程安全。如果locations集合不是非常大的話,這種做法通常不會造成性能問題。每次調用getLocations前先復制全部數據還會產生另一種副作用-即使真實的location已經改變,返回的容器的內容仍然不會改變

委托線程安全

我們向一個無狀態的類(假設A)中添加一個線程安全的類型(假設B)的屬性,所得組合對象仍然是線程安全的,因為A的狀態就是線程安全類B的狀態,并且A沒有對B的狀態增加額外的有效性的約束,可以說A將它的線程安全性委托給了B

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/128945.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息