主要的是讲多线程设计模式。。。其实有代码的,是java实现版的。。。。不过考虑到我说不定以后不怎么用java了,所以主要是把每个设计模式都列一个概述,思路总是有用的~~~所以觉得<Java多线程设计模式>这本书还是挺不错的~~~将每个多线程设计模式都用比较通俗易懂的语言来说明,而且代码都比较简单~~~~所以即使是不用java还是可以好好地理解一下多线程的魅力的~~~~
咔咔。。。写书的人总结得太好了。。。所以我只能上来他的笔记了。。。
1.Single Thread Execution Pattern
——能通过这座桥的,只有一个人
背景:——多个线程共享一个实例问题:——若多个线程都擅自更改实例的状态,实例会丧失安全性解决方式:——首先,找出实例状态不稳定的范围(临界区间),并对临界区间加以防止同时执行的线程保持在只有一条的情况。实现:——java里面用synchronized相关:——当实例的状态不会改变时,为了提升throughput,可使用Immutable Pattern。——想要将引用实例状态的线程与改变实例状态的线程拆开,以提高throughput时可使用Read-Write Lock Pattern
2.Immutable
——想破坏它也没办法
背景:——多个线程共享一个实例,实例的状态不会改变问题:——使用Single Threaded Execution Pattern,会降低throughput解决方式:——当实例建立后状态就不会再变化时,就要停止使用Single Threaded Execution Pattern了。——为了避免失误造成更改了实例的状态,故将类写成无法由线程更改。另外,删除实例里所有用来更新状态的方法(setter)。引用实例状态的方法(getter)就无妨实现:——java中使用private来隐藏字段,此外由于无法确保不可更改,因此还要使用final关联:——对多个线程进行共享互斥,可使用Single Threaded Execution Pattern。——当修改用的线程数量比用来读取的线程数量多时,可考虑使用Read-Write Lock
3.Guard Suspension
——要等到我准备好喔
背景:——多个线程共享一个实例问题:——若多个线程都擅自更改实例的状态,实例会丧失安全性解决方式:——当实例的状态不恰当时,就要求线程等待到适合的状态时。首先,以“警戒条件”来表示实例的“适当的状态”。并且在进行有安全性疑虑的操作前,都要检查是否警戒条件满足。如果警戒条件不成立,就要求线程等待到成立为止。——使用Guarded Suspension Pattern,能以警戒条件限制方法的执行。不过,如果警戒条件一直不成立,线程会永远等待下去,会使程序丧失生命性实现:——java中,检验警戒条件使用while语句,而要让线程等待时则使用wait方法。并使用notify/notifyAll通知警戒条件的改变。检验、修改警戒条件时,会使用到Single Threaded Execution Pattern相关:——当警戒条件不成立时想要马上退出,就使用BalkingPattern——Guarded Suspension Pattern中检验、更改警戒条件的部分,会使用到Single Threaded Execution Pattern
4.Balking
——不需要的话,就算了吧
背景:——多个线程共享一个实例问题:——若多个线程都擅自更改实例的状态,实例会丧失安全性。可以一直等待安全的时机,又会使程序响应性降低。解决方式:——当实例的状态不适合时,就会中断掉处理的进行。首先,以“警戒条件”来表示实例的“适当的状态”,并且在进行有安全性疑虑的操作前,都要检查是否满足警戒条件。只有在警戒条件成立时,才会执行;如果警戒条件不成立,就直接中断(balk)执行,马上退出。实现:——java语言中,检验警戒条件时要使用if语句。当要balk时,可使用return退出,或使用throw抛出异常,检验、修改警戒条件时,会使用到Single Threaded Execution Pattern关联:——当想要等到警戒条件成立再执行时,可使用Guarded Suspension Pattern。——Balking Pattern中检验、更改警戒条件的部分,会使用到Single Threaded Execution Pattern
5.Producer-Consumer
——我来做,你来用
背景:——当要从某个线程(Producer参与者)将数据传给其他线程(Consumer参与者)时问题:——当Producer参与者与Consumer参与者处理的速度不同时,速度慢的会扯速度快的后退,而降低程序的throughput。另外,当Producer参与者要写入数据时,Consumer参与者若同时读取数据,数据会丧失安全性。解决方式:——在Producer参与者与Consumer参与者之间,加上重击用的Channel参与者。并让Channel参与者存放多条数据。这样就可以缓冲Producer参与者与Consumer参与者之间处理速度的差异。另外,只要在Channel参与者里进行共享互斥,数据就不会丧失安全性。于是throughput可以不降低,又可以在多个线程之间安全地传送数据。相关:——Channel参与者安全传递数据的部分,使用了Guarded Suspension Pattern。——Future Pattern在传递返回值时,使用了Producer-Consumer Pattern——Worker Pattern在传递请求时,使用了Producer-Consumer Pattern
6.Read-Write Lock
——大家想看就看吧,不过看得时候不能写喔
背景:——多条线程共享一个实例,并会有参考实例状态的线程(Reader参与者),与会改变实例状体的线程(Writer参与者)问题:——若线程之间不进行共享互斥,会丧失安全性。但使用Single Threaded Execution Pattern会使程序throughput降低解决方式:——首先,将“控制Reader参与者的锁定”与“控制Writer参与者的锁定”分开,假如ReadWriteLock参与者,以提供两种不同的锁定。ReadWriteLock参与者会对“Writer参与者—Writer参与者”、“Reader参与者—Writer参与者”进行互斥控制。因为“Reader参与者-Reader参与者”不会发生冲突,故不会影响安全性,于是不进行共享互斥,这样可以在不影响安全性的前提下提高throughput实现:——java语言可以使用finally快避免忘记解除锁定。相关:——Read-Write Lock Pattern中,ReadWriteLock参与者进行共享互斥的地方,用到了Guarded Suspension Pattern——完全没有Writer参与者的时候,可使用Immutable Pattern
7.Thread-Per-Message
——这个工作交给你了
背景:——线程(Client参与者)要调用实例(Host参与者)的方法问题:——在方法的属性处理完之前,控制权不会从Host参与者退出。如果方法的处理属性花费时间,程序的响应性会降低解决方式:——在Host参与者里,启动新的线程。并将方法应该进行的工作,交割这个新的线程。这样Client参与者的线程就可以继续执行下一个操作了。这样做,不用更改Client参与者的程序代码,并能提高程序的响应性。实现:——java语言中,为了简化启动线程的程序,可使用匿名内部类相关:——想节省启动线程所花费的时间时,可以使用Worker Thread Pattern,想要将处理的结果返回给Client参与者时,可以使用Future Pattern
8.Worker Thread
——等到工作来,来了就工作
别名:——Thread Pool;Background Thread背景:——线程(Client参与者)要调用实例(Host参与者)的方法问题:——如果方法的处理属性很花时间,程序的响应性会降低。为了提高响应性,而启动新的线程来处理方法时,启动线程所花的时间又会降低throughput。另外,当送出的请求太多时,会启动过多的线程,这会使承载量变差。解决方法:——首先,我们事先启动一些用来进行处理的线程(工人线程)。并将代表请求的实例传给工人线程。这样就不需要每次都重新启动新的线程了。相关:——想要获取工人线程的处理结果时,可以使用Future Pattern想要将代表请求的实例传递给工人线程时,可以使用Producer-Consumer Pattern
9.Future
——先给您这张提货单
背景:——线程(Client参与者)会将工作委托给其他线程,而Client参与者希望得到处理的结果问题:——将工作委托给别人时,如果又等待执行结果,会使响应性降低解决方式:——首先,建立一个与处理结果具有相同接口的Future参与者。在处理开始时,先把Future参与者当作返回值返回。处理的结果事后再设置给Future参与者。这样Clinet参与者就可以在适当的时机,通过Future参与者,获取(等待)处理的结果。相关:等待Client参与者的处理结果时,会使用Guarded Suspension PatternFuture Pattern可用在Thread-Per-Message Pattern想要获取处理结果时。Future Pattern可用在Worker Thread Pattern想要获取获取处理结果时。
10.Two-Phase Termination
——快把玩具收拾好,去睡觉吧
背景:——想要结束运行中的程序问题:——从外部忽然结束掉线程,会丧失安全性。解决方式:——首先,适合进行终止的时机,还是要交给线程自己判断。所以,定义一个送出“终止请求”的方法用来结束线程:这个方法事实上只会将标识设置为“受到终止请求”而已,线程要在每个可以开始终止处理的地方自己检查这个标识。如果检查的结果为真,就开始进行终止处理。实现:——java语言中,不但要设置受到终止请求的标识,还要使用interrupt方法中断掉wait、sleep、join的等待状态。因为现场到wait、sleep、join抛出InterruptedException以后,就不是中断状态了,所以若是使用isInterrupted方法来检查终止请求,必须特别小心。为了在执行时发生异常也能确实进行终止处理,所以要使用finally块相关:——进行终止处理中时,为了禁止其他操作,可以使用Balking Pattern为了确实进行终止处理,使用了Before/After Pattern
11.Thread-Specific Storage
——每个线程的保管箱
背景:——想要将假定在单线程环境下运行的对象(TSObject参与者),在多线程的环境下使用。问题:——想要使用TSObject参与者并不简单。要将TSObject参与者改写成支持多线程,可能一部小心就丢掉安全性和生命性了。而且,TSObject参与者可能根本不能改写。而我们也不想改写使用TSObject参与者的对象(Client参与者)的程序代码,所以也不想修改TSObject参与者的接口。解决方式:——首先,建立一个与TSObject参与者具有相同接口的TSObjectProxy参与者,并建立TSObjectCollection参与者,管理“Client参与者->TSObject参与者”的对照关系TSObjectProxy参与者会通过TSObjectCollection参与者,获取当前线程所对应的TSObject参与者,并将工作委托给TSObject参与者。Client参与者会拿TSObjectProxy参与者来代替TSObject参与者使用。这样一来,每个TSObject参与者一定只会有特定的一个线程调用他,所以TSObject参与者不需要进行共享互斥,关于多线程的部分,都隐藏在TSObjectCollection参与者里了。另外,TSObject参与者的接口也不必修改。不过,使用Thread-Specific Storage Pattern,等于是在程序里加上隐性的context,有程序的可读性可能变差的危险性。实现:——java语言中,使用java.lang.ThreadLocal类担任TSObjectCollection参与者
12.Active Object
——接受异步消息的主动对象