java多线程(3)
Balking模式
Balk在这里的意思大概是“停止并返回”,棒球中的投手犯规就是这个词。在充分理解前面的Guarded Suspension模式后,学习Balking模式应该是相当容易的。我们可以看一下在某些场景下Guarded Suspension模式可能存在的缺点。Guarded Suspension模式中如果守护条件得不到满足,那么该线程将一直处于阻塞状态,在很多情况下,如上一篇文章中提到的多线程队列,而在另外的情况下,我们其实可以直接返回,而不必使线程阻塞,从而提高性能,这就是Balking模式。
比如在文本的自动保存中,我们可能会用到一个单独的定时启动的线程判断文本是否修改,如果没有修改(不满足守护条件),那么线程可以直接返回,而不必阻塞。由于思路只是在Guarded Suspension的基础上稍作改变,这里就不给出代码示例了。
Producer-Consumer模式
接下来是经典的生产者-消费者模型。生产者负责生产“商品”,消费者负责购买“商品”。当生产者和消费者都由同一个线程控制时,这似乎没有什么难的。但如果还原现实,生产者和消费者分别由单独的线程控制,甚至有多个生产者和消费者(多个线程),那么就需要一个桥梁来连接生产者和消费者。这个中介桥梁大多数情况是有限的,只能放置有限个商品。生产者生产的商品需要放到桥梁上,当桥梁满时,需要等待;而消费者需要通过桥梁购买商品,当桥梁上没有商品时,也需要等待。Producer-Consumer模式就是为了解决这种线程之间处理速度有差异的情况。
1 | public class Bridge { |
上述Brdige模拟的是生产者消费者沟通的桥梁,put由生产者调用,将商品放在桥梁里;get由消费者调用,获取放置在桥梁里的商品。如果您已经完全理解了之前的Guarded Suspension模式,那么也许会觉得get和put的逻辑无比简单。首先,get和put都必须被synchronized关键字修饰,即获得锁的线程才可以调用,避免冲突。其次,get和put方法的内部使用了Guarded Suspension模式。如果不满足守护条件,即生产者遇到buffer满的情况,或是消费者遇到buffer为0的情况,线程都会被阻塞,直到另外一方调用相应方法,进而notify。由此保证了当生产者和消费者不同步时,程序也能正常执行。
对InterruptedException异常的理解
该异常会由以下三个方法抛出:
- java.lang.Object.wait
- java.lang.Thread.join
- java.lang.Thread.sleep
InterruptedException表示该方法可能会花费时间,但可以取消。
- 花费时间。wait方法调用后线程会进入等待队列,直到notify’或notifyAll,sleep方法调用后线程会被暂停一定的时间,join方法调用后,线程会等待指定线程终止。
- 可以取消。对由于执行上述三个方法而暂停的线程t,可以由别的线程执行t.interrupt()来唤醒线程t,控制权会被传递给catch到InterruptedException的语句块。值得注意的是,wait方法的情况下,我们需要注意锁的情况,只有线程t重新获得锁,它才会抛出异常。
Thread-Per-Message模式
该模式直译就是每个消息一个线程,这里的消息主要指一些非常耗时的操作如IO等,意思就是把耗时的操作交给另外一个线程来执行,进而提高程序的相应性。这体现的是多线程程序的一个很重要的作用,就是提高程序的相应性,降低延迟。在Thread-Per-Message模式中,每一个message(耗时的操作)到来时,都会创建一个新的线程去执行,而主线程会立即返回,执行其他的操作。我们用Client来表示类似主线程的角色,由它来发起操作;用Host来表示负责创建线程的类;Helper类表示具体执行耗时操作的类。
1 | public class Helper { |
Host的实现使用了匿名内部类,把类的声明、创建、方法的调用结合在了一起,具体语法不在这里赘述。
Thread-Per-Message的主要目的是提高程序相应性,降低延迟,但在使用之前,我们需要注意它的一些特点,避免错误使用。
- 操作顺序无法保证。handle的执行并不一定会按照request的调用顺序,异常依赖于顺序的场景该模式是不适用的
- 没有返回值。handle方法是无法返回值的,因为request方法不会等待handle方法执行完就会返回。如果需要handle的返回值,可以考虑之后会介绍到的Future模式
Original author: 马旭
Original link: https://bhmaxu.github.io/2020/03/22/java多线程(3)/
Copyright Notice: Please indicate the source of the reprint (must retain the author's signature and link)