分享
 
 
 

驯服Java线程(三)

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

接上回!

避免同步

大部分显示的同步都可以避免。一般不操作对象状态信息(例如数据成员)的方法都不需要同步,例如:一些方法只访问本地变量(也就是说在方法内部声明的变量),而不操作类级别的数据成员,并且这些方法不会通过传入的引用参数来修改外部的对象。符合这些条件的方法都不需要使用synchronization这种重量级的操作。除此之外,还可以使用一些设计模式(Design Pattern)来避免同步(我将会在后面提到)。

你甚至可以通过适当的组织你的代码来避免同步。相对于同步的一个重要的概念就是原子性。一个原子性的操作事不能被其他线程中断的,通常的原子性操作是不需要同步的。

Java定义一些原子性的操作。一般的给变量付值的操作是原子的,除了long和double。看下面的代码:

class Unreliable

{

private long x;

public long get_x( ) {return x;}

public void set_x(long value) { x = value; }

}

线程1调用:

obj.set_x( 0 );

线程2调用:

obj.set_x( 0x123456789abcdef )

问题在于下面这行代码:

x = value;

JVM为了效率的问题,并没有把x当作一个64位的长整型数来使用,而是把它分为两个32-bit,分别付值:

x.high_word = value.high_word;

x.low_word = value.low_word;

因此,存在一个线程设置了高位之后被另一个线程切换出去,而改变了其高位或低位的值。所以,x的值最终可能为0x0123456789abcdef、0x01234567000000、0x00000000abcdef和0x00000000000000。你根本无法确定它的值,唯一的解决方法是,为set_x( )和get_x()方法加上synchronized这个关键字或者把这个付值操作封装在一个确保原子性的代码段里。

所以,在操作的long型数据的时候,千万不要想当然。强迫自己记住吧:只有直接付值操作是原子的(除了上面的例子)。其它,任何表达式,象x = ++y、x += y都是不安全的,不管x或y的数据类型是否是小于64位的。很可能在付值之前,自增之后,被其它线程抢先了(preempted)。

竞争条件

在术语中,对于前面我提到的多线程问题——两个线程同步操作同一个对象,使这个对象的最终状态不明——叫做竞争条件。竞争条件可以在任何应该由程序员保证原子操作的,而又忘记使用synchronized的地方。在这个意义上,可以把synchronized看作一种保证复杂的、顺序一定的操作具有原子性的工具,例如给一个boolean值变量付值,就是一个隐式的同步操作。

不变性

一种有效的语言级的避免同步的方法就是不变性(immutability)。一个自从产生那一刻起就无法再改变的对象就是不变性对象,例如一个String对象。但是要注意类似这样的表达式:string1 += string2;本质上等同于string1 = string1 + string2;其实第三个包含string1和string2的string对象被隐式的产生,最后,把string1的引用指向第三个string。这样的操作,并不是原子的。

由于不变对象的值无法发生改变,所以可以为多个线程安全的同步操作,不需要synchronized。

把一个类的所有数据成员都声明为final就可以创建一个不变类型了。那些被声明为final的数据成员并不是必须在声明的时候就写死,但必须在类的构造函数中,全部明确的初始化。例如:

Class I_am_immutable

{

private final int MAX_VALUE = 10;

private final int blank_final;

public I_am_immutable( int_initial_value )

{

blank_final = initial_value;

}

}

一个由构造函数进行初始化的final型变量叫做blank final。一般的,如果你频繁的只读访问一个对象,把它声明成一个不变对象是个保证同步的好办法,而且可以提高JVM的效率,因为HotSpot会把它放到堆栈里以供使用。

同步封装器(Synchronization Wrappers)

同步还是不同步,是问题的所在。让我们跳出这样的思维模式吧,世事无绝对。有什么办法可以使你的类灵活的在同步与不同步之间切换呢? 有一个非常好的现成例子,就是新近引入JAVA的Collection框架,它是用来取代原本散乱的、繁重的Vector等类型。Vector的任何方法都是同步的,这就是为什么说它繁重了。而对于collections对象,在需要保证同步的时候,一般会由访问它方法来保证同步,因此没有必要两次锁定(一次是锁定包含使用collection对象的方法的对象,一次是锁定collection对象自身)。Java的解决方案是使用同步封装器。其基本原理来自四人帮(Gang-of-Four)的Decorator模式,一个Decorator自身就实现某个接口,而且又包含了实现同样接口的数据成员,但是在通过外部类方法调用内部成员的相同方法的时候,控制或者修改传入的变量。java.io这个包里的所有类都是Decorator:一个BufferedInputStream既实现了虚类InputStream的所有方法,又包含了一个InputStream引用所指向的成员变量。程序员调用外部容器类的方法,实际上是变相的调用内部对象的方法。

我们可以利用这种设计模式。来实现灵活的同步方法。如下例:

Interface Some_interface

{

Object message( );

}

class Not_thread_safe implements Some_interface

{

public Object message( )

{

//实现该方法的代码,省~~~~~~~~~~~

return null;

}

}

class Thread_safe_wrapper implements Some_interface

{

Some_interface not_thread_safe;

public Thread_safe_wrapper(Some_interface not_thread_safe)

{

this.not_thread_safe = not_thread_safe;

}

public Some_interface extract( )

{

return not_thread_safe;

}

public synchronized Object message( )

{

return not_thread_safe.message( );

}

}

当不存在线程安全的时候,你可以直接使用Not_thread_safe类对象。当需要考虑线程安全的时候,只需要把它包装一下:

Some_interface object = new Not_thread_safe( );

……………

object = new Thread_safe_wrapper(object); //object现在变成线程安全了

当你不需要考虑线程安全的时候,你可以还原object对象:

object = ((Thread_safe_Wrapper)object).extract( );

下一回,我们又要深入底层机制了。呵呵!千万不要闷着大家呀!下回见!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有