JAVA并发设计模式学习笔记(一)—— JAVA多线程编程
这个专题主要讨论并发编程的问题,所有的讨论都是基于JAVA语言的(因其独特的内存模型以及原生对多线程的支持能力),不过本文传达的是一种分析的思路,任何有经验的朋友都能很轻松地将其扩展到任何一门语言。
注:本文的主要参考资料为结城浩所著《JAVA多线程设计模式》。
线程的英文名Thread,原意指“细丝”。在多线程程序中,若要追踪各个线程的轨迹,就会派生出一系列错综复杂的乱线团。假设在运行过程中,如果有人问到“请问现在执行到代码的哪一部分了?”,你需要多个手指头才能指出正确的地方。
当应用程序的规模、复杂程度达到一定程度时,并发设计是一个必将考虑到的问题,以下是一些常见的应用:
GUI:以word为例,我们正在编辑一份大型的文档,此时执行“查找”操作;当word进行查找时,同时会出现一个“停止查找”的按钮,用户可以随时停止。此时就用到了多线程,其中一个线程在后台执行查找,另一个线程显示“停止查找”的按钮,一旦按下,则立即停止查找。两个操作交由不同的线程来处理,各线程可以专心负责自己的功能,因此也是模块化设计思想的一种体现。比较耗时的I/O处理:由于磁盘、网络的IO操作消耗的时间远大于内存处理,如果在此段时间内,程序仅仅是等待而无法执行其它处理,性能会大打折扣。如果事先能将I/O处理和非I/O处理区分开来,这样就能够利用进行I/O处理时CPU空闲的间隙,进行其它处理了。一个Server与多个Client:大部分Server都要求能够同时服务于1个以上的Client。Server本身并不知道何时会有Client接入,并且在Server中直接引入多个Client的设计,并不是十分优雅的方案;因此不妨设计成一旦有Client连接到Server,就会生成自动出来迎接这个Client的线程。这样一来,Server端的程序就可以简单地设计成好像只服务一个Client。当然,从J2SE 1.4开始,已经加入了新的NIO类库,不必利用线程也能进行兼具性能和扩充性的I/O处理,详情可参考JDK。
至于JAVA中线程的编码方式,无非是继承自抽象类Thread或者实现Runnable接口,想必各位读者都很熟悉了,这里就不复述了。
在多线程程序里,多个线程既然可以自由操作,当然就可能同时操作到同一实例。这个情况又是会造成不必要的麻烦。例如经典的银行取款问题,其“确认可用余款”这一部分的代码应该该为:
class Something{ static void method() { synchronized(Something.class) { …… } }}