Single Threaded Execution模式

Single Threaded Execution模式

所谓Single Threaded Execution模式,意即“以一个线程执行”。就像独木桥同一时间只允许一个人通行一样,该模式用于设置限制,以确保同一时间内只能让一个线程执行处理。
Single Threaded Execution 有时候又被称作为临界区或临界域。Single Threaded Execution这个名称侧重于执行处理的线程,而临界区或临界域的名称侧重于执行范围。

不使用Single Threaded Execution模式的程序

类的一览表

名字 说明
Main 创建门,并让三个人不断通过的类
Gate 表示门的类。 它会在人们通过门时记录其姓名与出生地
UserThread 表示人的类。人们将不断地通过门

Main类

Main类将创建一个门,并让三个人不断地通过。首先Main类会创建Gate类的实例,并将该实例作为参数传递个UserThread类的构造函数。

1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args) {
Gate gate = new Gate();
new UserThread(gate, "Alice", "Alaska").start();
new UserThread(gate, "Bob", "Brazil").start();
new UserThread(gate, "Chris", "Canada").start();
}
}

非线程安全的Gate类

Gate类表示人通过的门。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Gate {
private int counter = 0; // 到目前为止通过的人数

private String name = "nobody";

private String address = "nowhere";

public void pass(String name, String address) { // 通过门,将通过人数+1,赋值人名和地址
this.counter++;
this.name = name;
this.address = address;
check();
}

public String toString() {
return "No." + counter + ": " + name + ", " + address;
}

private void check() { // 检查当前门的状态
if (name.charAt(0) != address.charAt(0)) {
System.out.println("******** BROKEN ********" + toString());
}
}
}

UserThread类

UserThread表示不断通过门的人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class UserThread extends Thread {
private final Gate gate;

private final String myName;

private final String myAddress;

public UserThread(Gate gate, String myName, String myAddress) {
this.gate = gate;
this.myName = myName;
this.myAddress = myAddress;
}

public void run() {
System.out.println(myName + " begin");
while(true) {
gate.pass(myName, myAddress);
}
}

}

非线程安全类执行结果

为什么会出错

因为pass方法会被多个线程执行,此处是3个。pass方法包含下面四条语句:

1
2
3
4
this.counter++
this.name = name
this.address = address
check()

这里以两个线程举两个错误的例子。
线程Alice和线程Bobby执行pass方法的情形1

线程Alice 线程Bob this.name的值 this.address的值
this.counter++ this.counter++ (之前的值) (之前的值)
“Bobby” (之前的值)
this.name = name “Alice” (之前的值)
this.address = address “Alice” “Alaska”
this.address = address “Alice” “Brazil”
check() check() “Alice” “Brazil”
***** BROKEN *****
线程Alice和线程Bobby执行pass方法的情形2
线程Alice 线程Bob this.name的值 this.address的值
this.counter++ this.counter++ (之前的值) (之前的值)
this.name = name “Alice” (之前的值)
this.name = name “Bobby” (之前的值)
this.address = address “Bobby” “Brazil”
this.address = address “Bobby” “Alaska”
check() check() “Bobby” “Brazil”
***** BROKEN *****

使用Single Threaded Execution模式的程序

这边只要将Gate类改为线程安全的类即可,其他的类不需要修改。

线程安全的Gate类

分别有两处修改,在pass和toString方法签名中加入了synchronized关键字,这样一来Gate类就变成了线程安全的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Gate {
private int counter = 0;

private String name = "nobody";

private String address = "nowhere";

public synchronized void pass(String name, String address) {
this.counter++;
this.name = name;
this.address = address;
check();
}

public synchronized String toString() {
return "No." + counter + ": " + name + ", " + address;
}

private void check() {
if (name.charAt(0) != address.charAt(0)) {
System.out.println("******** BROKEN ********" + toString());
}
}
}

如图所示: 无论执行多久,都不会再有其他输出。

线程安全类执行结果

线程Alice和线程Bobby执行pass方法的情形1

线程Alice 线程Bob this.name的值 this.address的值
获取锁
this.counter++ (之前的值) (之前的值)
this.name = name “Alice” (之前的值)
this.address = address “Alice” “Alaska”
check() “Alice” “Alaska”
释放锁
获取锁
this.count++ “Alice” “Alaska”
this.name = name “Bobby” “Alaska”
this.address = address “Bobby” “Brazil”
check() “Bobby” “Brazil”
释放锁

线程Alice和线程Bobby执行pass方法的情形2

线程Alice 线程Bob this.name的值 this.address的值
获取锁
this.counter++ (之前的值) (之前的值)
this.name = name “Bobby” (之前的值)
this.address = address “Bobby” “Brazil”
check() “Bob” “Brazil”
释放锁
获取锁
this.count++ “Bobby” “Brazil”
this.name = name “Alice” “Brazil”
this.address = address “Alice” “Alaska”
check() “Alice” “Alaska”
释放锁

参考

《图解Java多线程设计模式》

0%