在多線程環境中,爲了保證共享數據的一致性,每每須要對共享數據的使用進行加鎖,可是加鎖操做自己就會帶來必定的開銷,這裏可使用將共享數據使用不可變對象進行封裝,從而避免加鎖操做。java
不可變對象指的是,對象內部沒有提供任何可供修改對象數據的方法,若是須要修改共享變量的任何數據,都須要先構建整個共享對象,而後對共享對象進行總體的替換,經過這種方式來達到對共享對象數據一致性的保證。以下是不可變對象設計的類圖:git
以下是各個角色功能的描述:多線程
對於不可變對象,其主要有以下三種使用場景:this
對於不可變對象,一個很好的例子就是地址經緯度。筆者所工做的公司處理的業務和房源相關,其中有一部分就是須要處理房源所在點的經緯度信息,這裏就可使用不可變對象,由於房源經緯度基本上不會發生變化,而且對其操做也主要是以查詢爲主,最重要的是,對經緯度的處理必須是經度和緯度同時發生變化,任何狀況下只更改了其中一個數據都會產生問題。以下是記錄房源經緯度的類:線程
public final class Location { private final long id; private final String latitude; private final String longitude; public Location(long id, String latitude, String longitude) { this.id = id; this.latitude = latitude; this.longitude = longitude; } public long getId() { return id; } public String getLatitude() { return latitude; } public String getLongitude() { return longitude; } }
該Location類也即上述UML類圖中的ImmutableObject部分。能夠看到,任何對Location對象的修改都必須從新構建一個Location對象。以下是對Location的管理類,用於存儲具體的Location信息的:設計
public class LocationHolder { private final LocationHolder INSTANCE = new LocationHolder(); private Map<Long, Location> locations; private LocationHolder() { this.locations = new ConcurrentHashMap<>(); } public LocationHolder getInstance() { return INSTANCE; } public Location getLocation(long id) { return locations.get(id); } public void addLocation(long id, String latitude, String longitude) { Location location = new Location(id, latitude, longitude); locations.put(id, location); } public Map<Long, Location> getLocations() { return Collections.unmodifiableMap(locations); } }
能夠看到,這裏對Location的管理是經過一個單例類LocationHolder進行的,任何對Location的操做都進行了封裝,而且這裏批量獲取Location,也是返回了一個不可變Map,從而保證原始數據不會做任何修改,若是該Map的鍵或值任何一方可能發生變化,那麼在返回值則必須返回一個深度複製的結果,這樣才能保證原始數據的完整性。code