所谓Single Threaded Execution 模式,意思是“以一个线程执行”。就像独木桥同一时间只允许一个人通行一样,该模式用于 设置限制,以确保同一时间只能让一个线程执行处理。
不安全的代码:
非安全的Gate:
/**
* 大门
* @author Administrator
*
*/
public class Gate {
private int counter = 0;//表示目前为止已经通过这道门的人数
private String name = "NoBody";//表示通行者的姓名
private String address = "NoWhere";//表示该人的出生地
/**
* 表示的是通过门,该方法将表示通过人数的counter字段的值递增1,并将参数中传入的通行者的姓名和出生地
**/
public void pass(String name, String address) {
this.counter++;
this.name = name;
this.address = address;
check();
}
private void check() {
//如果name与address首字母不同,那么说明记录数据是异常的
if (name.charAt(0) != address.charAt(0)) {
System.out.println("****** BROEKN ******" + toString());
}
}
public String toString() {
return "No." + counter + ":" + name + "," + address;
}
}
UserThread类:不断通过门的人
/**
* 用户线程
* @author Administrator
*
*/
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) {
super();
this.gate = gate;
this.myname = myname;
this.myaddress = myaddress;
}
@Override
public void run() {
System.out.println(myname + " BEGIN");
//不断循环,并在循环中反复调用pass方法来表示这个人在门里不断的穿梭过去
for (;;) {
gate.pass(myname, myaddress);
}
}
}
测试类:Main
public class Main {
public static void main(String[] args) {
Gate gate = new Gate();
new UserThread(gate, "Alice", "Alaska").start();
new UserThread(gate, "Bobby", "Brazil").start();
new UserThread(gate, "Chris", "Canada").start();
}
}
运行结果:
当Gate类的实例被多个线程使用时,运行结果与预期不一致,也就是说,这个Gate类是不安全的,是非线程安全的。
为什么会出错:
情形1:线程Alice和线程Bobby执行pass的:
线程Alice | 线程Bobby | this.name的值 | this.address的值 |
this.counter++ | this.counter++ | 之前的值 | 之前的值 |
this.name=name | “Bobby” | 之前的值 | |
this.name = name | Alice | 之前的值 | |
this.address= address |
情形2:线程Alice和线程Bobby执行pass的:
线程Alice | 线程Bobby | 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 | Alaska |
***** BROKEN ***** | |||
线程安全带的Gate:
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();
}
private void check() {
// 当某个人的name首字母和地址的首字母一样的时候,打印语句
if (name.charAt(0) != address.charAt(0)) {
System.out.println("****** BROEKN ******" + toString());
}
}
public synchronized String toString() {
return "No." + counter + ":" + name + "," + address;
}
}
线程Alice和线程Bobby执行synchronized修饰的pass方法的情形:
线程Alice | 线程Bobby | this.name的值 | this.address的值 |
[获取锁] | |||
this.counter++ | 之前的值 | 之前的值 | |
this.name=name | Alice | 之前的值 | |
this.adderss=address | Alice | Alaska | |
check() | Alice | Alaska | |
[释放锁] | |||
[获取锁] | |||
this.counter++ | Alice | Alaska | |
this.name=name | Bobby | Alaska | |
this.adderess=address | Bobby | Brazil | |
check(); | Bobby | Brazil | |
[释放锁] |
关于synchronized
不管是synchronized 方法还是synchronized代码块,
synchronized 方法
synchronized void method(){
...........
}
synchronized (obj){
...........
}
无论哪种,都可以看作在"{"处获取锁,在"}"处释放锁。
显示处理锁的方法:
void method(){
lock();
.........
unlock()
}
存在return时,锁无法被释放:
void method{
lock();
if(条件表达式){
return;//此处如果执行return,unlock()就不会被调用
}
unlock();
}
doMethod抛出异常时,锁无法被释放:
void method(){
lock();
doMethod();//如果该方法只用抛出异常,unlock()就不会被调用
unlock();
}
相对地,synchronized方法和synchronized代码块无论是执行return还是抛出异常,都一定能够释放锁。
调用lock()方法之后,无论执行什么操作,都会调用unlock方法;
void method(){
lock();
try{
}finally{
unlock();
}
}
上述代码无论是return、抛出异常还是其他任何操作,finally部分都会被调用到。