Java并发编程规则设计线程安全的类.docx
- 文档编号:6666908
- 上传时间:2023-01-08
- 格式:DOCX
- 页数:16
- 大小:18.31KB
Java并发编程规则设计线程安全的类.docx
《Java并发编程规则设计线程安全的类.docx》由会员分享,可在线阅读,更多相关《Java并发编程规则设计线程安全的类.docx(16页珍藏版)》请在冰豆网上搜索。
Java并发编程规则设计线程安全的类
Java并发编程规则:
设计线程安全的类
封装设计:
尽管所有的状态都存储在公共静态变量(域)中,仍然能写出线程安全的程序,但比起那些适当封装的类来说,我们难以验证这种程序的线程安全性,也很难再修改它的同步不破坏它的线程安全性。
在没有进行全局检查的情况下,封装能够保证线程的安全性。
=====设计线程安全类的过程应该包括下面3个基本要素:
========
1、确定对象状态是由哪些变量组成的;
2、确定限制状态变量的不变约束;
3、制定一个管理并发访问对象状态的策略。
同步策略方式:
对状态使用同步策略,以维护其不变约束。
需要明确的是同步的需求是什么,并分析其不可变约束和后验条件。
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importnet.jcip.annotations.*;
/**
*Counter
*
*Simplethread-safecounterusingtheJavamonitorpattern
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicfinalclassCounter{
@GuardedBy("this")privatelongvalue=0;
publicsynchronizedlonggetValue(){
returnvalue;
}
publicsynchronizedlongincrement(){
if(value==Long.MAX_VALUE)
thrownewIllegalStateException("counteroverflow");
return++value;
}
}
注:
不理解对象的不可变约束和后验条件,就不能保证线程的安全性。
要约束状态变量的有效值或者状态转换,就需要原子性与封装性。
实例限制:
限制性使构造线程安全的类更容易。
因为类的状态被限制后,分析它的线程安全性时,就不必检查完整的程序。
将数据封装在实体内部,把对数据的访问限制在对象的方法上,更易确保线程在访问数据时总能获得正确的锁。
示例如下:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importjava.util.*;
importnet.jcip.annotations.*;
/**
*PersonSet
*
*Usingconfinementtoensurethreadsafety
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicclassPersonSet{
@GuardedBy("this")privatefinalSet
publicsynchronizedvoidaddPerson(Personp){
mySet.add(p);
}
publicsynchronizedbooleancontainsPerson(Personp){
returnmySet.contains(p);
}
interfacePerson{
}
}
HashSet是一个线程安全的类,通过公开的方法进行同步读写操作,确保了线程的安全性。
Java监视器模式:
像Vector和HashTable这样的核心库类,都是采用了Java监视器模式,其最大优势在于简单。
Java监视器模式仅仅是一种习惯约定:
任意锁对象只要始终如一地使用,都可以用来保护对象的状态。
来看个私有锁保护状态的示例:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importnet.jcip.annotations.*;
/**
*PrivateLock
*
*Guardingstatewithaprivatelock
*
*@authorBrianGoetzandTimPeierls
*/
publicclassPrivateLock{
privatefinalObjectmyLock=newObject();
@GuardedBy("myLock")Widgetwidget;
voidsomeMethod(){
synchronized(myLock){
//Accessormodifythestateofwidget
}
}
}
实际上同步策略中Counter.java也是一个简单的Java监视器模式的示例。
下面是一个基于监视器的机动车追踪器:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importjava.util.*;
importnet.jcip.annotations.*;
/**
*MonitorVehicleTracker
*
*Monitor-basedvehicletrackerimplementation
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicclassMonitorVehicleTracker{
@GuardedBy("this")privatefinalMap
publicMonitorVehicleTracker(Map
this.locations=deepCopy(locations);
}
publicsynchronizedMap
returndeepCopy(locations);
}
publicsynchronizedMutablePointgetLocation(Stringid){
MutablePointloc=locations.get(id);
returnloc==null?
null:
newMutablePoint(loc);
}
publicsynchronizedvoidsetLocation(Stringid,intx,inty){
MutablePointloc=locations.get(id);
if(loc==null)
thrownewIllegalArgumentException("NosuchID:
"+id);
loc.x=x;
loc.y=y;
}
privatestaticMap
Map
for(Stringid:
m.keySet())
result.put(id,newMutablePoint(m.get(id)));
returnCollections.unmodifiableMap(result);
}
}
packagenet.jcip.examples;
importnet.jcip.annotations.*;
/**
*MutablePoint
*
*MutablePointclasssimilartojava.awt.Point
*
*@authorBrianGoetzandTimPeierls
*/
@NotThreadSafe
publicclassMutablePoint{
publicintx,y;
publicMutablePoint(){
x=0;
y=0;
}
publicMutablePoint(MutablePointp){
this.x=p.x;
this.y=p.y;
}
}
委托线程安全:
委托线程安全,就是使用现有的线程安全的类来实现线程安全,即由其代为控制线程安全。
下面来看个使用委托的机动车追踪器,ConcurrentMap线程安全委托:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importjava.util.*;
importjava.util.concurrent.*;
importjava.awt.*;
importjava.awt.Point;
importnet.jcip.annotations.*;
/**
*DelegatingVehicleTracker
*
*DelegatingthreadsafetytoaConcurrentHashMap
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicclassDelegatingVehicleTracker{
privatefinalConcurrentMap
privatefinalMap
publicDelegatingVehicleTracker(Map
locations=newConcurrentHashMap
unmodifiableMap=Collections.unmodifiableMap(locations);
}
publicMap
returnunmodifiableMap;
}
publicPointgetLocation(Stringid){
returnlocations.get(id);
}
publicvoidsetLocation(Stringid,intx,inty){
if(locations.replace(id,newPoint(x,y))==null)
thrownewIllegalArgumentException("invalidvehiclename:
"+id);
}
//AlternateversionofgetLocations(Listing4.8)
publicMap
returnCollections.unmodifiableMap(
newHashMap
}
}
packagenet.jcip.examples;
importnet.jcip.annotations.*;
/**
*Point
*
*ImmutablePointclassusedbyDelegatingVehicleTracker
*
*@authorBrianGoetzandTimPeierls
*/
@Immutable
publicclassPoint{
publicfinalintx,y;
publicPoint(intx,inty){
this.x=x;
this.y=y;
}
}
Point是不可变对象,它是线程安全的。
来看一下将线程安全委托到多个隐含变量:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importjava.awt.event.KeyListener;
importjava.awt.event.MouseListener;
importjava.util.*;
importjava.util.concurrent.*;
/**
*VisualComponent
*
*Delegatingthreadsafetytomultipleunderlyingstatevariables
*
*@authorBrianGoetzandTimPeierls
*/
publicclassVisualComponent{
privatefinalList
privatefinalList
publicvoidaddKeyListener(KeyListenerlistener){
keyListeners.add(listener);
}
publicvoidaddMouseListener(MouseListenerlistener){
mouseListeners.add(listener);
}
publicvoidremoveKeyListener(KeyListenerlistener){
keyListeners.remove(listener);
}
publicvoidremoveMouseListener(MouseListenerlistener){
mouseListeners.remove(listener);
}
}
注:
如果一个类由多个彼此独立的线程安全的状态变量组成,并且类的操作不包含任何无效状态转换时,可以将线程安全委托给这些变量。
如果一个状态变量是线程安全的,没有任何不变约束限制它的值,并且没有任何状态转换限制它的操作,那么它可以被安全地发布。
安全发布状态:
底层可变的状态也可以是线程安全的类。
示例:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importnet.jcip.annotations.*;
/**
*SafePoint
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicassSafePoint{
@GuardedBy("this")privateintx,y;
privateSafePoint(int[]a){
this(a[0],a[1]);
}
publicSafePoint(SafePointp){
this(p.get());
}
publicSafePoint(intx,inty){
this.set(x,y);
}
publicsynchronizedint[]get(){
returnnewint[]{x,y};
}
publicsynchronizedvoidset(intx,inty){
this.x=x;
this.y=y;
}
}
packagenet.jcip.examples;
importjava.util.*;
importjava.util.concurrent.*;
importnet.jcip.annotations.*;
/**
*PublishingVehicleTracker
*
*Vehicletrackerthatsafelypublishesunderlyingstate
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicclassPublishingVehicleTracker{
privatefinalMap
privatefinalMap
publicPublishingVehicleTracker(Map
this.locations=newConcurrentHashMap
this.unmodifiableMap=Collections.unmodifiableMap(this.locations);
}
publicMap
returnunmodifiableMap;
}
publicSafePointgetLocation(Stringid){
returnlocations.get(id);
}
publicvoidsetLocation(Stringid,intx,inty){
if(!
locations.containsKey(id))
thrownewIllegalArgumentException("invalidvehiclename:
"+id);
locations.get(id).set(x,y);
}
}
扩展已有线程安全类:
重要思想:
缺少即加入。
扩展Vector为例:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importjava.util.*;
importnet.jcip.annotations.*;
/**
*BetterVector
*
*ExtendingVectortohaveaput-if-absentmethod
*
*@authorBrianGoetzandTimPeierls
*/
@ThreadSafe
publicclassBetterVector
//Whenextendingaserializableclass,youshouldredefineserialVersionUID
staticfinalgserialVersionUID=-3963416950630760754L;
publicsynchronizedbooleanputIfAbsent(Ex){
booleanabsent=!
contains(x);
if(absent)
add(x);
returnabsent;
}
}
使用客户端加锁(缺少即加入):
明确可变约束,加锁的位置很重要。
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
packagenet.jcip.examples;
importjava.util.*;
importnet.jcip.annotations.*;
/**
*ListHelder
*
*Examplesofthread-safeandnon-thread-safeimplementationsof
*put-if-absenthelpermethodsforList
*
*@authorBrianGoetzandTimPeierls
*/
@NotThreadSafe
classBadListHelper
publicList
publicsynchronizedbooleanputIfAbsent(Ex){
booleanabsent=!
list.contains(x);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 并发 编程 规则 设计 线程 安全