文章目录
1.1 模式简介
- 有一座独木桥,非常细,每次只允许一个人经过。如果这个人还没有走到桥的另一头,则下一个人无法过桥。如果同时有两个人上桥,桥就会塌掉,掉进河里。
- Single Threaded Execution模式,意即 “以一个线程执行”。就像独木桥同一时间内只允许一个人通行一样,该模式用于设置限制,以确保同一时间内只能让一个线程执行处理。
- Single Threaded Execution有时候也称为临界区(critical section)或临界域(critical region)。
- Single Threaded Execution 这个名称侧重于执行处理的线程(过桥的人),而临界区或临界域的名称则侧重于执行范围(人过的桥)。
1.4 Single Threaded Execution模式中的角色
1.4.1 SharedResource(共享资源)
- SharedResource角色是可被多个线程访问的类,例如 ThroughGate中的 Gate 类。它包含很多方法,但这些方法主要分为如下两类:
- safeMethod:多个线程同时调用也不会发生问题的方法。
- unsafeMethod:多个线程同时调用会发生问题,因此必须加以保护的方法。
- 可以通过将 unsafeMethod 声明为 synchronized 方法来进行保护。
- 我们将只允许单个线程执行的程序范围称为临界区。
1.4.2 类图和Timethreads图
1.5 拓展思路的要点
1.5.1 何时使用
- 多线程时
- 多个线程访问时
- 当ShareResource角色的实例有可能被多个线程同时访问时,就需要使用Single Threaded Execution模式。
- 即便是多线程程序,如果所有线程都是完全独立操作的,那么也无需使用Single Threaded Execution模式。这种状态称为线程互不干涉(interfere)。
- 状态有可能发生变化时
- 之所以需要使用Single Threaded Execution模式,是因为ShareResource角色的状态会发生变化。
- 如果在创建实例后,实例的状态再也不会发生变化,那就无需使用Single Threaded Execution模式。
- 需要确保安全性时
- 例如,Java的集合类大多都是非线程安全的。这是为了在不需要考虑安全性的时候提高程序运行速度。
1.5.2 生存性与死锁
- 在使用Single Threaded Execution模式时,会存在发生死锁的危险。死锁是指两个线程分别持有着锁,并相互等待对方释放锁的现象。发生死锁的线程都无法再继续运行,程序也就失去了生存性。
- 在Single Threaded Execution模式中,满足下列条件时,死锁就会发生:
- 存在多个SharedResource角色 ;
- 线程在持有着某个SharedResource角色的锁的同时,还想获取其他 SharedResource角色的锁;
- 获取SharedResource角色的锁的顺序并不固定(SharedResource角色是对称的)
只要破坏三个条件中的一个,就可以防止死锁发生。
1.8 计数信号量和Semaphore类
- Single Threaded Execution模式用于确保某个区域 “只能由一个线程” 执行。将这种模式进一步扩展,以确保某个区域 “最多只能由N个线程” 执行,这时就要用计数信号量来控制线程数量。
- java.util.concurrent包提供了表示计数信号量的Semaphore类。
- 资源的许可个数(permits)将通过semaphore的构造函数来指定。
- Semaphore的 acquire 方法用于确保存在可用资源。当存在可用资源时,线程会立即从acquire方法返回,同时信号量内部的资源个数会减1。如无可用资源,线程则阻塞在acquire方法内,直至出现可用资源。
- Semaphore的 release 方法用于释放资源。释放资源后,信号量内部的资源个数会增加1。另外,如果acquire中存在等待的线程,那么其中一个线程会被唤醒,并从acquire方法返回。