西宁兄弟连IT培训学校

试听课 + 活动课
填写信息优先获取试听课

位置:学校首页 > 学校动态>Java编写线程安全类的7个技巧

Java编写线程安全类的7个技巧

几乎每个Java应用程序都会用到线程。例如,Tomcat是在单独的工作线程中处理每个请求,胖客户机(Fat Client)在专用工作线程中处理长时间运行的请求。本文将跟你一起探讨如何以线程安全的方式来编写类。

一、无状态(No State)

当多个线程访问相同的实例或静态变量时,必须以某种方式来协调对此变量的访问。较简单的方法就是避免使用实例或静态变量。对于没有实例变量的类,它的方法只使用局部变量和方法参数。以下示例显示了java.lang.Math类的其中一部分:

二、无共享状态(No Shared State)

如果你必须要使用状态,那么请不要共享状态,即状态应该只属于一个单一的线程。这种技术的一个例子是SWT或Swing图形用户界面框架的事件处理线程。您可以通过扩展Thread类并添加实例变量来实现“本地线程”(thread-local)实例变量。在以下示例中,pool和workQueue对于单个工作线程是本地的。

另一种实现线程局部变量的方法是使用java.lang.ThreadLocal类来作为你想创建“本地线程”的字段。这是一个使用java.lang.ThreadLocal的实例变量的例子:

在java.lang.ThreadLocal中封装实例变量的类型。您可以通过initialValue()方法为您的java.lang.ThreadLocal提供一个初始值。

以下显示如何使用实例变量:

通过调用get()方法,您将可以获取到与当前线程关联的对象。

在服务器环境中,使用了许多线程池来处理请求,因此java.lang.ThreadLocal会导致在此环境中消耗大量内存。因此,不推荐java.lang.ThreadLocal用于服务器处理请求线程。

三、使用消息传递(Message Passing)

如果您不使用上述技术共享状态,则可以通过线程之间相互传递消息的方式来实现。您可以使用java.util.concurrent包中的并发队列实现消息传递。或者,更好的做法是,使用像Akka这样的框架。以下示例显示如何使用Akka发送消息:

然后是接收消息:

四、使用不变状态(Immutable State)

为了避免发送线程在另一个线程读取消息时更改消息的问题,消息应该是不可变的。因此,Akka框架有一个约定,就是所有的消息必须是不可变的。当你实现一个不可变类的时候,你应该把它的字段声明为final。这不仅确保编译器可以检查字段实际上是不可变的,而且即使在发布不正确时也能正确初始化。这里是一个实例变量的例子:

五、使用java.util.concurrent包中的数据结构

消息传递使用并发队列进行线程之间的通信,并发队列是java.util.concurrent包中提供的数据结构之一。这个包提供了并发map、queue、dequeue、set、list等相关类。这些数据结构经过高度优化,并经过线程安全性测试。

六、使用同步块

如果以上提到的方法都不适合你,那么,你可以使用同步块,也就是在同步块当中加锁,这样,你将可以确保在同一时刻只有一个线程可以执行该部分代码。

七、将变量声明为volatile

正常情况下,变量可以缓存在寄存器或缓存中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。通过声明一个变量为volatile,你告诉JVM和编译器,该变量每次被线程访问时,都强迫从共享内存中重新读取。以下显示了一个volatile变量的例子:

不过,对于volatile的使用,其实网上是有一定争议的,具体请自行百度。

领取试听课
温馨提示:为不影响您的学业,来校区前请先电话或QQ咨询,方便我校安排相关的专业老师为您解答
版权所有:搜学搜课(www.soxsok.com) 技术支持:搜学搜课网