一、简介

所谓Single Threaded Execution模式,就是指“以一个线程执行”,就像一座独木桥同一时间内只允许一个人通过一样,该模式用于设置限制,以确保同一时间内只能让一个线程执行处理。

二、实例(无Single Threaded Execution)

首先,我们来看一下应该使用Single Threaded Execution模式却没有使用的程序,体会一下在多线程下无法正确执行的程序会引发什么现象。

  • 一次只允许一个人通过的门。
类名 说明
Main.java 创建门,并让三个人不断地通过的类
Gate.java 表示门的类,它会在人通过时记录其姓名和出生地
UserThread.java 表示人的类,人们将不断地通过门

1.Gate类,代码如下:

package com.viagra.Single_Threaded_Execution.Not_Haved;/*** @Auther: viagra* @Date: 2019/11/19 11:11* @Description:*/
public class Gate {protected int conuter = 0;protected String name = "Nobody";protected String address = "Nowhere";/*** 非安全线程* @param name* @param address*/public void pass(String name, String address) {this.conuter++;this.name = name;this.address = address;check();}/*** toString返回* @return*/public String toString() {return "No." + conuter + ": " + name + "," + address;}/*** 检查name和adress的首字母是否项目,不相同则为异常数据*/private void check(){if(name.charAt(0) != address.charAt(0)){System.out.println("******* 不一致 ********:"+toString());}}
}

2.UserThread类,代码如下:

package com.viagra.Single_Threaded_Execution.Not_Haved;/*** @Auther: viagra* @Date: 2019/11/19 11:13* @Description:*/
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;}public void run() {System.out.println(myname + " 开始:");while (true) {gate.pass(myname, myaddress);}}
}

3.Main类,三名通行者分别如下:

  • Steve Nash,出生于San Francisco;
  • Michael Jordan,出生于Miami;
  • Ronaldo,出生于Rome。

代码如下:

package com.viagra.Single_Threaded_Execution.Not_Haved;/*** @Auther: viagra* @Date: 2019/11/19 11:14* @Description:*/
public class Main {public static void main(String[] args) {System.out.println("测试Single Threaded Execution-Gate,hit CTRL+C to exit.");Gate gate = new Gate();new UserThread(gate, "Steve Nash", "San Francisco").start();new UserThread(gate, "Michael Jordan", "Miami").start();new UserThread(gate, "Ronaldo", "Rome").start();}
}

4.测试,运行Main中的主类,运行结果:*(出错了)*

测试Single Threaded Execution-Gate,hit CTRL+C to exit.Steve Nash 开始:Ronaldo 开始:Michael Jordan 开始:******* 不一致 ********:No.193689: Michael Jordan,Miami******* 不一致 ********:No.194489: Michael Jordan,Miami******* 不一致 ********:No.194959: Michael Jordan,Miami.........******* 不一致 ********:No.3190046: Ronaldo,Miami******* 不一致 ********:No.3190492: Ronaldo,Rome******* 不一致 ********:No.3191505: Michael Jordan,Miami******* 不一致 ********:No.3194400: Michael Jordan,Rome******* 不一致 ********:No.3194951: Michael Jordan,Miami******* 不一致 ********:No.3196153: Ronaldo,Miami******* 不一致 ********:No.3196968: Michael Jordan,Miami******* 不一致 ********:No.3198653: Michael Jordan,Rome

说明:在程序执行到193689行的时候(),******* 不一致 ********的标识就打印出来了,原因是因为Gate类是非线程安全的。

5.错误原因:

在执行程序的时候,pass()方法会被多个线程执行,pass方法包含下面4个语句:

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

对于name和address来说,几个线程会分别相互操作,获胜的一个线程会先写入值,而此时,对于name和address的值而言,其结果就不得而知了。

三、实例(有Single Threaded Execution)

我们将Gate类修改为线程安全的类,Main和UserThread方法不用做修改,使用synchronized关键字进行修饰。

1.Gate类,代码如下:

package com.viagra.Single_Threaded_Execution.Haved.Lesson1;/*** @Auther: viagra* @Date: 2019/11/19 11:18* @Description:*/
public class Gate {private int conuter = 0;private String name = "Nobody";private String address = "Nowhere";/*** 加上synchronized* @param name* @param address*/public synchronized void pass(String name, String address){this.conuter++;this.name = name;this.address = address;check();}/*** 加上synchronized* toString返回* @return*/public synchronized String toString() {return "No." + conuter + ": " + name + "," + address;}/*** 检查name和adress的首字母是否项目,不相同则为异常数据*/private void check(){if(name.charAt(0) != address.charAt(0)){System.out.println("******* 不一致 ********:"+toString());}}
}

2.运行程序,结果如下:

测试Single Threaded Execution-Gate,hit CTRL+C to exit.
Steve Nash 开始:
Ronaldo 开始:
Michael Jordan 开始:

无论等多久,都不会显示“******* 不一致 ********”的信息,说明通过加上synchronized后,方法的安全性会很高。

3.synchronized的作用

synchronized方法能够确保方法同时只能有一个线程执行,也就是说,在线程Steve Nash执行pass方法的时候,线程Michael Jordan和Ronaldo就无法再执行pass方法,只能等线程Steve Nash执行完pass方法后,释放锁以后,其他的线程才能开始执行pass方法。

四、Single Threaded Execution模式中的登场角色

  • SharedResource(共享资源)

在上面的实例中,由Gate扮演这SharedResource角色。SharedResource角色是可被多个线程访问的类,包含的方法有很多,但这些方法主要分为以下二类:

  • safeMethod:安全的,多个线程同时调用也不会发生问题。

  • unsafeMethod:非安全的,多个线程同时调用会发生问题。

  • 何时使用
  1. 多线程时;
  2. 多个线程访问时;
  3. 状态有可能发生变化时;
  4. 需要确保安全时。
  • 临界区的大小和性能

一般情况下,Single Threaded Execution模式会降低程序性能,原因有二个:

  1. *获取锁花费时间;*
  2. *线程冲突引起的等待。*

五、关于synchronized

不管是synchronized方法,还是synchronized代码块,都是由“{”,“}”括起来的代码块。

synchronized void method(){  ...}
synchronized (obj){  ...}

无论是哪种,都可以看作在“{”处获取锁,在“}”处释放锁。下面我们比较一下使用synchronized的代码与显示处理锁的代码,假设存在一个获取锁的lock方法和一个释放锁的unlock方法。

void method(){   lock(); ... unlock();}

是不是认为“这虽然看起来有点复杂,但和使用synchronized的代码也没有什么大的区别”?其实区别很大,如果在lock方法和unlock方法之间存在return,那么锁就无法被释放。

不仅return的时候锁无法被释放,在遇到异常处理的时候,锁依旧无法被释放。如果doMethod抛出异常时,锁无法被释放。

void method(){   lock(); doMethod(); unlock();}

如果想让一个防范能够同时成对执行lock()和unlock(),那么可以使用finally来实现:

void method() {lock();try {} catch (Exception e) {       ...} finally {unlock();}}

不管是return还是异常处理,还是其他操作,finally部分都会被调用,这是Java规范。

  • synchronized在保护什么?

synchronized就像是门上的锁,当看到门上的锁时,我们还应该确认其他的门和窗户是不是都锁好了,只要是访问多个线程共享的字段方法,就需要使用synchronized进行保护。

线程要执行synchronized的实例方法,必须获取this的锁,而能够获得一个实例的说的线程只有一个,正是因为这种唯一性,才能够使synchronized来实现Single Threaded Execution模式。

六、java.util.concurrent包和计数信号量

1.计数信号量和Semaphore类

Single Threaded Execution模式用户确保某个区域“只能由一个线程”执行,下面通过这种模式扩展,以确保某个区域“最多只能由N个线程”执行,就要用计数信号量来控制线程量。

2.实例,代码如下:

//使用Semaphore类的示例程序
public class SemaphoreMain {public static void main(String[] args) {//设置3个资源BoundedResource boundedResource = new BoundedResource(3);//10个线程调用资源for (int i = 0; i < 10; i++) {new UserThread(boundedResource).start();}}}//日志
class Log {public static void println(String s) {System.out.println(Thread.currentThread().getName() + "==>:" + s);}
}//资源个数有限
class BoundedResource {private final Semaphore semaphore;private final int permits;private final static Random random = new Random(314159);public BoundedResource(int permits) {this.semaphore = new Semaphore(permits);this.permits = permits;}//使用资源public void use() throws InterruptedException {semaphore.acquire();try {doUse();} catch (Exception e) {e.printStackTrace();} finally {semaphore.release();}}//实际使用资源protected void doUse() throws InterruptedException {Log.println("BEGIN: used = " + (permits - semaphore.availablePermits()));Thread.sleep(random.nextInt(500));Log.println("END: used = " + (permits - semaphore.availablePermits()));}
}class UserThread extends Thread {private final static Random random = new Random(26535);private final BoundedResource boundedResource;public UserThread(BoundedResource boundedResource) {this.boundedResource = boundedResource;}public void run() {try {while (true) {boundedResource.use();Thread.sleep(random.nextInt(3000));}} catch (InterruptedException e) {e.printStackTrace();}}
}

3.执行结果:

Thread-0==>:BEGIN: used = 1Thread-1==>:BEGIN: used = 3Thread-0==>:END: used = 3Thread-3==>:BEGIN: used = 3Thread-3==>:END: used = 3Thread-5==>:BEGIN: used = 3Thread-1==>:END: used = 3Thread-6==>:BEGIN: used = 3Thread-5==>:END: used = 3Thread-4==>:BEGIN: used = 3Thread-4==>:END: used = 3Thread-8==>:BEGIN: used = 3Thread-7==>:END: used = 3Thread-2==>:BEGIN: used = 3Thread-6==>:END: used = 3Thread-9==>:BEGIN: used = 3Thread-2==>:END: used = 3Thread-9==>:END: used = 2

七、Lock类

在上面的实例程序中,不在Gate类中使用synchronized,该如果实现Single Threaded Execution模式?

其实可以是使用Mutes类,像Mutes类这样执行互斥处理的机制通常成为Mutex。

代码如下:

package com.viagra.Single_Threaded_Execution.Haved.Lesson3;import java.util.concurrent.locks.ReentrantLock;/*** @Auther: viagra* @Date: 2019/11/19 12:26* @Description:*/
public class Gate {private int conuter = 0;private String name = "Nobody";private String address = "Nowhere";private final ReentrantLock mutex = new ReentrantLock();;/*** 加上Mutex* @param name* @param address*/public void pass(String name, String address){mutex.lock();try{this.conuter++;this.name = name;this.address = address;check();}catch (Exception e){e.printStackTrace();}finally {mutex.unlock();}}/*** 加上Mutex* toString返回* @return*/public String toString() {String s = null;mutex.lock();try{s = "No." + conuter + ": " + name + "," + address;}catch (Exception e){e.printStackTrace();}finally {mutex.unlock();}return s;}/*** 检查name和adress的首字母是否项目,不相同则为异常数据*/private void check(){if(name.charAt(0) != address.charAt(0)){System.out.println("******* 不一致 ********:"+toString());}}
}

执行结果:()

测试Single Threaded Execution-Gate,hit CTRL+C to exit.Michael Jordan 开始:Steve Nash 开始:Ronaldo 开始:

代码案例

java多线程之Single Threaded Execution模式相关推荐

  1. Single Threaded Execution模式

    以下是学习了<图解Java多线程设计模式>一书中记录的内容 Single Threaded Execution模式--能通过这座桥的只有一个人 Single Threaded Execut ...

  2. 一 、Single Threaded Execution 模式

    当我们修改多个线程共享的实例时,实例就会失去安全性.所以,我们应该仔细找出实例状态不稳定的范围,将这个范围设为临界区,并对临界区进行保护,使其只允许一个线程同时执行. JAVA使用synchroniz ...

  3. 第一章Single Threaded Execution模式 能通过这座桥的只有一个人

    [Single Threaded Execution模式] 以一个线程执行,就像独木桥同一时间内只允许一个人通行一样,该模式用于设置限制.以确保同一时间内只能让一个线程执行处理. Single Thr ...

  4. 多线程编程模式之Single Threaded Execution 模式

    一.Single Threaded Execution 模式介绍 简单的来说,Single threaded execution 模式描述了在一种多线程环境下各个线程对于公用资源的使用方式--任一时刻 ...

  5. java single threaded_[Java多线程设计模式]读书笔记 - 第一章 Single Threaded Execution

    Single Threaded Execution是指"以1个线程执行"的意思.就像细独木桥只允许一个人通行一样,这个Pattern用来限制同时只让一个线程运行. Single T ...

  6. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  7. Java多线程之Callable、Future和FutureTask

    Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...

  8. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  9. Java多线程之CAS缺点

    Java多线程之CAS缺点 目录: 循环时间开销很大 只能保证一个共享变量的原子操作 引来ABA问题及解决方案(重点) 1. 循环时间开销很大 通过看源码,我们发现有个do while,如果CAS失败 ...

最新文章

  1. 每天5道面试题(二)java基础
  2. DevExpress WinFormsSuite 本地化(Simplified Chinese OR Traditional Chinese)
  3. Eureka restTemplate访问超时
  4. [JQuery] jQuery选择器ID、CLASS、标签获取对象值、属性、设置css样式
  5. CSDN移动博文集锦之Android核心分析 (Z)
  6. 解决maven项目中,缺少 maven dependencies
  7. 重磅开源!《30天吃掉那只 TensorFlow2.0 》(附下载)
  8. 断代、新生、创未来-Zoomla!逐浪CMS2 x3.9.6全面发布...
  9. 利用条件随机场模型进行中文分词
  10. 程序员算法之找出链表的第K个结点
  11. Opencv之Meanshift和Camshift
  12. web渗透--rpcbind利用
  13. IntelliJ IDEA教程()ideaIU-快速创建测试用例
  14. 《C#之集训1-20121019c#基础》
  15. 【十大思想实验之中的一个】电车难题
  16. 关于0xffffffff 到底是什么意思?
  17. 理财就是理生活读后感
  18. JAVA实现篮球计分计时器
  19. 同态加密中的一些技术概念
  20. 服务器Connections could not be acquired from the underlying database错误

热门文章

  1. 通过注册表方式启动和关闭手写输入法(方法适合各种应用)
  2. Pandas函数read_csv的参数na_values的用法
  3. canvas 贝萨尔曲线
  4. 计算机域名设置方法,windows电脑加入域的设置方法步骤(图文)
  5. python byte和str转换
  6. web的邮件抄送和密送
  7. zend guard loader php ts,安装Zend Guard Loader说明
  8. openwrt 内网域名 解析错误
  9. 解决Heroku“ name is already taken“问题
  10. 智能井盖被纳入《城市综合管廊运营服务规范》国标,喜大普奔