【第48条】对共享可变数据的同步访问

《第9章 线 程》

 

    通过使用线程(thread)可以在同一程序中同时进行多个活动。多线程程序设计比单线程程序设计要困难得多。所以如果一个类库可以帮助你从低层的多线程程序设计中解脱出来,那么一定要使用这个类。即使这样,有时候仍然要编写或者维护多线程代码,所以本章包含的建议可以帮助我们写出清晰、正确、文档组织良好的多线程程序。

 

【第48条】对共享可变数据的同步访问

 

<我的废话:>

    如今我们喜爱Java、使用Java,很大情况下是由于Java的稳定、强大的表现,丰富的类库资源和出色的跨平台性。这些优势在使用Java作为B/S结构编程中的S的实现时都表现得淋漓尽致。然而,当我们广泛采用Java语言作为服务器端开发语言时,由于B/S系统的特点,我们可能很少关系多线程编程了。

 

    B/S的并发访问,本身就是多线程的,它往往已经由Servlet容器或EJB容器来完成了,我们所需要编写的“服务”只需要关心如何去处理一个客户端的访问即可。在这种情形下,多线程编程往往就被遗忘了。尤其是在企业应用开发和网站开发中,对某一客户的一次服务请求时,大多数情况下是用不着多线程的(业务逻辑没有复杂到那个份上)。

 

    然而,对于那些静态属性和单例模式的对象来说,就必须考略到他们的同步了。就是那些用于在不同客户间传递信息的单例对象和用于记录整个系统(网站)的某些状态的静态属性。

 

    言归正传,synchronized关键字可以保证在同一时刻,只有一个线程在执行被它“保护”起来的代码块。当一个线程在修改一个对象时,其他线程都不会看到对象处于不一致的状态中。或者说,当一个线程在同步代码块中修改一个对象时,其他线程也进入这个代码块时,看到的对象的状态仍然是第一线程修改前的状态;当第一个线程结束修改离开同步代码块后,其他线程再看此对象就是修改后的状态了。比较类似于数据库修改前的select for update。

 

    为了在线程之间可靠地通信,以及为了互斥访问,同步是需要的。如果有“为了提高性能而避免使用同步”的建议,那么这样的建议是非常危险而错误的。举一个例子:

 

    一个网站中有一个计数器,以提示来访者是第几位访客。

private static int visitorCounter = 0;

public static int getVisitorCounter(){
    return ++visitorCounter;
}

 

   这里显然使用一个静态的属性来保存全站全局性的计数器。当一个访客访问时,通过静态的getVisitorCounter()方法返回是第几位来访者。这个方法,首先将计数器加一,然后将加一后的数值返回,然而就是这个++运算实际是先取得对象的状态,再修改对象的状态。那么当多线程并发访问时(多个访问者同时访问此网页),不加同步的方法就有可能产生这样的效果:

 

    线程1取得visitorCounter为888887,此时线程2也取得了visitorCounter为888887,然后线程1将它取得的数值加一得到888888并返回,之后线程也将它取得的数值加一得到888888并返回。结果就是两个不同的访问者都看到自己是第888888位来访者。如果这个网站在之前的宣传中承诺将为幸运的第888888位访客提供丰厚的奖品的话,那么他们就有麻烦了,可能有好几位网友都拿着截屏来领奖了(PS的不算)。

 

    那么这个该如何防止呢?答案就是给方法以同步保护:

private static int visitorCounter = 0;

public static synchronized int getVisitorCounter(){
    return ++visitorCounter;
}

 

   这样就避免了当一个线程正在读/写对象状态时,被另一个线程读到“不稳定”的状态。

 

   总而言之,无论何时,当多个线程共享可变数据的时候,每个读或者写数据的线程必须获得一把锁。

 

 

 

 

【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值