多线程编程一个需要注意的问题是线程安全问题,即多线程并发对某个资源进行修改,导致数据混乱。这也是缺乏经验的网站工程师最容易犯错的地方,而线程安全Bug又难以测试和重现,网站故障中,许多所谓偶然发生的“灵异事件”都和多线程并发问题有关。对网站而言,不管有没有进行多线程编程,工程师写的每一行代码都会被多线程执行,因为用户请求是并发提交的,也就是说,所有的资源——对象、内存、文件、数据库,乃至另一个线程都可能被多线程并发访问。
编程上,解决线程安全的主要手段有如下几点:
一、将对象设计为无状态对象
所谓无状态对象是指对象本身不存储状态信息(对象无成员变量,或者成员变量也是无状态对象),这样多线程并发访问的时候就不会出现状态不一致,Java Web开发中常用的Servlet对象就设计为无状态对象,可以被应用服务器多线程并发调用处理用户请求。而Web开发中常用的贫血模型对象都是些无状态对象。不过从面向对象设计的角度看,无状态对象是一种不良设计。
二、使用局部对象
即在方法内部创建对象,这些对象会被每个进入该方法的线程创建,除非程序有意识地将这些对象传递给其他线程,否则不会出现对象被多线程并发访问的情形。
三、并发访问资源时使用锁
即多线程访问资源的时候,通过锁的方式使多线程并发操作转化为顺序操作,从而避免资源被并发修改。随着操作系统和编程语言的进步,出现各种轻量级锁,使得运行期线程获取锁和释放锁的代价都变得更小,但是锁导致线程同步顺序执行,可能会对系统性能产生严重影响。
参考资料:大型网站技术架构核心原理与案例分析
完结!