这里有一座独木桥。因为桥身非常的细,一次只能允许一个人通过。当这个人没有下桥,另一个人就不能过桥。如果桥上同时又两个人,桥就会因为无法承重而破碎而掉落河里。 这就是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,这样就可以了。

多线程设计模式(一) Single Threaded Execution的更多相关文章

  1. JAVA并发设计模式学习笔记(二)—— Single Threaded Execution Pattern

    注:本文的主要参考资料为结城浩所著<JAVA多线程设计模式>. 单线程执行模式(Single Threaded Execution Pattern)是最简单的多线程设计模式,几乎所有其他的 ...

  2. 多线程程序设计学习(2)之single threaded execution pattern

    Single Threaded Execution Pattern[独木桥模式] 一:single threaded execution pattern的参与者--->SharedResourc ...

  3. 多线程学习之一独木桥模式Single Threaded Execution Pattern

    Single Threaded Execution Pattern[独木桥模式] 一:single threaded execution pattern的参与者--->SharedResourc ...

  4. Java多线程设计模式(一)

    目录(?)[-] Java多线程基础 Thread类的run方法和start方法 线程的启动 线程的暂时停在 线程的共享互斥 线程的协调 Single Threaded Execution Patte ...

  5. Java多线程设计模式(二)

        目录(?)[-] Guarded Suspension Pattern Balking Pattern Producer-Consumer Pattern   Guarded Suspensi ...

  6. Java多线程设计模式(1)

    1 线程中的几个方法解释 Thread.sleep(long 毫秒) 在指定的时间内让当前线程休眠,将控制权交给其他线程,休眠的线程依旧拥有它所占用的锁, Thread.yield(); 暂停或者放弃 ...

  7. 图解java多线程设计模式之一一synchronized实例方法体

    synchronized实例方法体和synchronized代码块 synchronied void method(){ ....... } 这个等同于下面将方法体用synchronized(this ...

  8. 多线程系列之二:Single Thread Execution 模式

    一,什么是SingleThreadExecution模式?同一时间内只能让一个线程执行处理 二,例子 1.不安全的情况 用程序模拟 三个人频繁地通过一个只允许一个人经过的门.当人通过时,统计人数便会增 ...

  9. 多线程设计模式——Read-Write Lock模式和Future模式分析

    目录 多线程程序评价标准 任何模式都有一个相同的"中心思想" Read-Write Lock 模式 RW-Lock模式特点 冲突总结 手搓RW Lock模式代码 类图 Data类 ...

随机推荐

  1. atom 隐藏右边的白线

    atom-text-editor.editor .wrap-guide {//隐藏右边的白线visibility: hidden;}

  2. xamarin studio 安装

    公司wpf项目移植到mac,用到mono来进行重写,不会,自己开搞 首先一个问题Xamarin怎么读,xaml熟悉吧,xaml读作Zamel,xamarin也就读作Zamerin,恩,就是它了... ...

  3. 11gR2 RAC 独占模式replace votedisk遭遇PROC-26,restore ocr遭遇CRS-4000、PROT-35

    原文链接:http://blog.itpub.net/23135684/viewspace-748816/ 11gR2 RAC系统的存储数据全然丢失,全部节点的软件都安装在本地磁盘中.本地磁盘保留了O ...

  4. [反汇编练习] 160个CrackMe之028

    [反汇编练习] 160个CrackMe之028. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  5. 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)

    随笔分类 - webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...

  6. 从零開始开发Android版2048 (二)获取手势信息

    今天是尝试開始Android版2048小游戏的第二天.在今天,我主要学习了怎样获取用户在屏幕滑动的手势,以及对布局进行了一些小小的完好. 获取用户操作的手势(比方向左滑.向右滑等)主要用到了Gestu ...

  7. HDU 4403 A very hard Aoshu problem (DFS暴力)

    题意:给你一个数字字符串.问在字符串中间加'='.'+'使得'='左右两边相等. 1212  : 1+2=1+2,   12=12. 12345666 : 12+3+45+6=66.  1+2+3+4 ...

  8. asp .net 为图片添加图片水印 .

    首先写好一个写入图片水印的类,先创建一个ImageWriter类库   (该类中有包含枚举类型和方法) using System; using System.Collections.Generic; ...

  9. session写入数据库

    <?php class session { private static $handle = null; private static $ip = null; private static $l ...

  10. 用算法求N(N&gt;=3)之内素数的个数

    首先.我们谈一下素数的定义.什么是素数?除了1和它本身外,不能被其它自然数整除(除0以外)的数 称之为素数(质数):否则称为合数. 依据素数的定义,在解决问题上,一開始我想到的方法是从3到N之间每一个 ...