首页
学习
活动
专区
工具
TVP
发布

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)

然后是接收消息:

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

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

六、使用同步块

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

七、将变量声明为volatile

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

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

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180117A035U400?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券