欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Single Threaded Execution 模式

程序员文章站 2022-07-13 11:02:54
...

所谓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();
    }
}

运行结果:

Single Threaded Execution 模式

当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  
Alaska this.address=addressAliceBrazilcheck()check()AliceBrazil  ***** BROKEN ***** 

情形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;
	}

}

Single Threaded Execution 模式


线程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部分都会被调用到。