zoukankan      html  css  js  c++  java
  • 多线程设计模式(一) Single Threaded Execution

    这里有一座独木桥。因为桥身非常的细,一次只能允许一个人通过。当这个人没有下桥,另一个人就不能过桥。如果桥上同时又两个人,桥就会因为无法承重而破碎而掉落河里。 这就是Single Threaded Execution。有时也称为Critical section(临界区)。

    这个模式用来限制同时只允许一个线程运行。

    首先,我们先来看一个应该使用该设计模式,但是却没有使用的案例:

    在这里要写一个程序,用来模拟3个人频繁的通过一扇只允许一个人通过的门。当有人通过门时,门上的记录器会递增通过的人数,另外还会记录通过的人的姓名和出生地。

    Main类,用来创建一个Grte门,并让3个人UserThread不断的通过该门。

    public class Main {
    	public static void main(String[] args) {
    		Gate gate = new Gate();
    		new UserThread(gate,"a","aaa").start();
    		new UserThread(gate,"b","bbb").start();
    		new UserThread(gate,"c","ccc").start();
    	}
    }
    Gate类,表示人所要通过的门

    	private int counter = 0;//通过的人数
    	private String name = "Nobody";//通过人的姓名
    	private String address = "Nowhere";//通过人的地址
    	
    	//使人通过该门
    	public void pass(String name,String address){
    		counter++;
    		this.name=name;
    		this.address=address;
    		check();
    	}
    	
    	@Override
    	public String toString() {
    		return "NO."+counter+",:"+name+","+address;
    	}
    	//验证通过时记录的姓名和地址是否是同一个人
    	//如果不是,则输出BROKEN
    	public void check() {
    		if(!address.contains(name)){
    			System.out.println("----BROKEN----"+toString());
    		}
    	}
    }

    UserThread 表示不断穿过门的行人。通过集成Thread来实现。

    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");
    		while(true){//使一个人不断的重复通过要通过的门
    			gate.pass(myName, myAddress);
    		}
    	}
    }

    执行程序,打印结果为:

    ----BROKEN----NO.34584635,:c,ccc
    ----BROKEN----NO.34584719,:b,bbb
    ----BROKEN----NO.34584817,:c,ccc
    ----BROKEN----NO.34584920,:a,ccc
    ----BROKEN----NO.34585274,:a,aaa
    ----BROKEN----NO.34585674,:b,bbb
    通过执行结果可以得出,Gate类,在多线程的情况下执行,Gate类这时并不安全。

    而有时,明明姓名和地址是同一个人,程序依然会报错。这是由于:某个线程在执行check方法是,其他线程还在调用pass方法,name和address值又被修改了。


    下面,将Gate类修改成线程安全的类,其他类则不需要修改:

    //门
    public class Gate {
    	private int counter = 0;//通过的人数
    	private String name = "Nobody";//通过人的姓名
    	private String address = "Nowhere";//通过人的地址
    	
    	//使人通过该门
    	public synchronized void pass(String name,String address){
    		counter++;
    		this.name=name;
    		this.address=address;
    		check();
    	}
    	
    	@Override
    	public synchronized String toString() {
    		return "NO."+counter+",:"+name+","+address;
    	}
    	//验证通过时记录的姓名和地址是否是同一个人
    	//如果不是,则输出BROKEN
    	public void check() {
    		if(!address.contains(name)){
    			System.out.println("----BROKEN----"+toString());
    		}else{
    			System.out.println(toString());
    		}
    	}
    }
    

    执行结果如下:

    NO.52446,:c,ccc
    NO.52447,:c,ccc
    NO.52448,:c,ccc
    NO.52449,:c,ccc
    NO.52450,:c,ccc
    NO.52451,:c,ccc
    NO.52452,:c,ccc
    NO.52453,:c,ccc
    NO.52454,:c,ccc
    NO.52455,:c,ccc
    NO.52456,:c,ccc
    无论等多久都没有BROKEN


    为什么在pass方法和toString方法上加synchronized就不在显示BROKEN了呢?
    正如前面所说,之所以显示BROKEN是有限pass方法被多个线程穿插执行。加synchronized,能保证只有一个线程执行它。

    而check方法,只有pass方法能调用它,所以其他类无法调用check方法,所以,不需要设置成synchronized(设置也没有关系,但是可能会影响程序性能)。toString 加上synchronized的原因是由于,在其他线程调用toString方法是,可能存在在获取name和adress是不一致的情况。

    synchronized 方法同时只有一个线程能进行操作,从多线程的角度看,是“原子的操作”,本意是不可分割的操作。

    在java中,基本数据类型(primitive)如int, char, byte等都是原子性操作的,但是long和double则不一定,所以我们想把long和double这类非原子性类型按照原子性方式操作,需要加上关键字volatile,这样就可以了。

  • 相关阅读:
    JAVA -数据类型与表达式---表达式
    JAVA -数据类型与表达式---基本数据类型
    【网易官方】极客战记(codecombat)攻略-森林-背靠背-back-to-back
    【网易官方】极客战记(codecombat)攻略-森林-荆棘农场thornbush-farm
    【网易官方】极客战记(codecombat)攻略-森林-村庄守护者
    【网易官方】极客战记(codecombat)攻略-森林-If 的盛宴
    【网易官方】极客战记(codecombat)攻略-森林-鹰眼
    【网易官方】极客战记(codecombat)攻略-森林-野餐毁灭者
    【网易官方】极客战记(codecombat)攻略-森林-巡逻兵克星A
    【网易官方】极客战记(codecombat)攻略-森林-巡逻兵克星
  • 原文地址:https://www.cnblogs.com/xsyfl/p/6842523.html
Copyright © 2011-2022 走看看