Java并发编程规则设计线程安全的类.docx

上传人:b****6 文档编号:6666908 上传时间:2023-01-08 格式:DOCX 页数:16 大小:18.31KB
下载 相关 举报
Java并发编程规则设计线程安全的类.docx_第1页
第1页 / 共16页
Java并发编程规则设计线程安全的类.docx_第2页
第2页 / 共16页
Java并发编程规则设计线程安全的类.docx_第3页
第3页 / 共16页
Java并发编程规则设计线程安全的类.docx_第4页
第4页 / 共16页
Java并发编程规则设计线程安全的类.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

Java并发编程规则设计线程安全的类.docx

《Java并发编程规则设计线程安全的类.docx》由会员分享,可在线阅读,更多相关《Java并发编程规则设计线程安全的类.docx(16页珍藏版)》请在冰豆网上搜索。

Java并发编程规则设计线程安全的类.docx

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")privatefinalSetmySet=newHashSet();

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")privatefinalMaplocations;

publicMonitorVehicleTracker(Maplocations){

this.locations=deepCopy(locations);

}

publicsynchronizedMapgetLocations(){

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;

}

privatestaticMapdeepCopy(Mapm){

Mapresult=newHashMap();

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{

privatefinalConcurrentMaplocations;

privatefinalMapunmodifiableMap;

publicDelegatingVehicleTracker(Mappoints){

locations=newConcurrentHashMap(points);

unmodifiableMap=Collections.unmodifiableMap(locations);

}

publicMapgetLocations(){

returnunmodifiableMap;

}

publicPointgetLocation(Stringid){

returnlocations.get(id);

}

publicvoidsetLocation(Stringid,intx,inty){

if(locations.replace(id,newPoint(x,y))==null)

thrownewIllegalArgumentException("invalidvehiclename:

"+id);

}

//AlternateversionofgetLocations(Listing4.8)

publicMapgetLocationsAsStatic(){

returnCollections.unmodifiableMap(

newHashMap(locations));

}

}

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{

privatefinalListkeyListeners=newCopyOnWriteArrayList();

privatefinalListmouseListeners=newCopyOnWriteArrayList();

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{

privatefinalMaplocations;

privatefinalMapunmodifiableMap;

publicPublishingVehicleTracker(Maplocations){

this.locations=newConcurrentHashMap(locations);

this.unmodifiableMap=Collections.unmodifiableMap(this.locations);

}

publicMapgetLocations(){

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

publicclassBetterVectorextendsVector{

//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{

publicListlist=Collections.synchronizedList(newArrayList());

publicsynchronizedbooleanputIfAbsent(Ex){

booleanabsent=!

list.contains(x);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1