java多线程之Single Threaded Execution模式
一、简介
所谓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个语句:
- this.conuter++;
- this.name = name;
- this.address = address;
- 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:非安全的,多个线程同时调用会发生问题。
- 何时使用
- 多线程时;
- 多个线程访问时;
- 状态有可能发生变化时;
- 需要确保安全时。
- 临界区的大小和性能
一般情况下,Single Threaded Execution模式会降低程序性能,原因有二个:
- *获取锁花费时间;*
- *线程冲突引起的等待。*
五、关于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模式相关推荐
- Single Threaded Execution模式
以下是学习了<图解Java多线程设计模式>一书中记录的内容 Single Threaded Execution模式--能通过这座桥的只有一个人 Single Threaded Execut ...
- 一 、Single Threaded Execution 模式
当我们修改多个线程共享的实例时,实例就会失去安全性.所以,我们应该仔细找出实例状态不稳定的范围,将这个范围设为临界区,并对临界区进行保护,使其只允许一个线程同时执行. JAVA使用synchroniz ...
- 第一章Single Threaded Execution模式 能通过这座桥的只有一个人
[Single Threaded Execution模式] 以一个线程执行,就像独木桥同一时间内只允许一个人通行一样,该模式用于设置限制.以确保同一时间内只能让一个线程执行处理. Single Thr ...
- 多线程编程模式之Single Threaded Execution 模式
一.Single Threaded Execution 模式介绍 简单的来说,Single threaded execution 模式描述了在一种多线程环境下各个线程对于公用资源的使用方式--任一时刻 ...
- java single threaded_[Java多线程设计模式]读书笔记 - 第一章 Single Threaded Execution
Single Threaded Execution是指"以1个线程执行"的意思.就像细独木桥只允许一个人通行一样,这个Pattern用来限制同时只让一个线程运行. Single T ...
- JAVA多线程之wait/notify
本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...
- Java多线程之Callable、Future和FutureTask
Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...
- Java多线程之Synchronized和Lock的区别
Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...
- Java多线程之CAS缺点
Java多线程之CAS缺点 目录: 循环时间开销很大 只能保证一个共享变量的原子操作 引来ABA问题及解决方案(重点) 1. 循环时间开销很大 通过看源码,我们发现有个do while,如果CAS失败 ...
最新文章
- 每天5道面试题(二)java基础
- DevExpress WinFormsSuite 本地化(Simplified Chinese OR Traditional Chinese)
- Eureka restTemplate访问超时
- [JQuery] jQuery选择器ID、CLASS、标签获取对象值、属性、设置css样式
- CSDN移动博文集锦之Android核心分析 (Z)
- 解决maven项目中,缺少 maven dependencies
- 重磅开源!《30天吃掉那只 TensorFlow2.0 》(附下载)
- 断代、新生、创未来-Zoomla!逐浪CMS2 x3.9.6全面发布...
- 利用条件随机场模型进行中文分词
- 程序员算法之找出链表的第K个结点
- Opencv之Meanshift和Camshift
- web渗透--rpcbind利用
- IntelliJ IDEA教程()ideaIU-快速创建测试用例
- 《C#之集训1-20121019c#基础》
- 【十大思想实验之中的一个】电车难题
- 关于0xffffffff 到底是什么意思?
- 理财就是理生活读后感
- JAVA实现篮球计分计时器
- 同态加密中的一些技术概念
- 服务器Connections could not be acquired from the underlying database错误
热门文章
- 通过注册表方式启动和关闭手写输入法(方法适合各种应用)
- Pandas函数read_csv的参数na_values的用法
- canvas 贝萨尔曲线
- 计算机域名设置方法,windows电脑加入域的设置方法步骤(图文)
- python byte和str转换
- web的邮件抄送和密送
- zend guard loader php ts,安装Zend Guard Loader说明
- openwrt 内网域名 解析错误
- 解决Heroku“ name is already taken“问题
- 智能井盖被纳入《城市综合管廊运营服务规范》国标,喜大普奔