java多线程设计模式笔记之Single Thread Execution
来源:互联网 发布:剑三同人知乎 编辑:程序博客网 时间:2024/05/17 01:28
现在有三个人要循环随机通过一个门,三个人的名字和国家首字母都一样,每当一个人通过门的时候,就检查这个人和国家是否一致,不一致则报错BROKEN.程序如下:
门:
import java.awt.Checkbox;public class Gate {private int count = 0;private String name = "Nobody";private String country = "Nowhere";public void name() {} void pass(String name,String address) {// TODO Auto-generated method stubthis.count++;this.name = name;this.country = address;Check();}public String toString() {return "No."+count+":"+name+","+country;}private void Check() {// TODO Auto-generated method stubif(name.charAt(0) != country.charAt(0)){System.out.println("BROKEN*************"+toString());}}}人(每个人穿越是独立的,故为一个线程)
public class UserThread extends Thread{private Gate gate;private String myname;private String mycountry;public UserThread(Gate gate, String name, String country) {this.gate = gate;this.myname = name;this.mycountry = country;}public void run() {// TODO Auto-generated method stubSystem.out.println(myname+"BEGIN");while (true) {gate.pass(myname, mycountry);}}}客户端程序:
public class Main {public static void main(String[] args){System.out.println("Testing Gate");Gate gate = new Gate();new UserThread(gate, "Bobe", "Brazil").start();new UserThread(gate, "Chen", "China").start();new UserThread(gate, "Alice", "America").start();}}每个人的名字首字母都和国家首字母一样,感觉应该不会出现BROKEN,但是看下结果:
Testing Gate
BobeBEGIN
AliceBEGIN
ChenBEGIN
BROKEN*************No.432:Alice,America
BROKEN*************No.543:Alice,Brazil
BROKEN*************No.811:Chen,America
BROKEN*************No.543:Alice,Brazil
BROKEN*************No.811:Chen,America
BROKEN*************No.1521:Alice,America
BROKEN*************No.1765:Alice,America
BROKEN*************No.2142:Alice,China
BROKEN*************No.1078:Alice,America
BROKEN*************No.2554:Bobe,Brazil
BROKEN*************No.2834:Bobe,Brazil
BROKEN*************No.3111:Alice,Brazil
BROKEN*************No.2142:Alice,China
BROKEN*************No.3495:Alice,America
(以下省略n条记录。。)
My god!出好多问题了!
为什么呢?因为所有线程共享一份数据——Gate对象,它是线程不安全的。在这个过程中,
this.count++;this.name = name;this.country = address;Check();是被三个线程交错调用的,要通过竞争来确定谁先执行。可能出现一个线程在调用完pass的时候,恰好另一个线程调用pass中给name赋值却还没及时给country赋值,结果前者check的时候发现name和country不一致,于是BROKEN,所以打印出来的名字和国家不一致。
注意到,在BROKEN中也有很多名字和国家一致的,这又是怎么回事?
同样因为Gate的线程不安全,前者在调用check的时候,后者调用pass将name和country同时修改了,于是又一致了。
如何让Gate线程安全呢?很简单,在被各个线程写数据的pass加上synchronized:
public synchronized void pass(String name,String address) {// TODO Auto-generated method stubthis.count++;this.name = name;this.country = address;Check();}结果很给力~~
Testing GateBobeBEGINAliceBEGINChenBEGINsynchronized简单来说就是确保一个时刻只有一个线程访问对应的代码,其他线程在等待知道里面的线程执行完毕。而一般对于
多线程程序来说,对于多个线程同时执行的时候会使得对象的状态出现矛盾的方法,就要用synchronized来保护。synchronized实际上
是让线程得到一把锁(一般锁存在于对象中),只有持有锁的线程才可以执行,执行完synchronized代码块才释放锁。当一个线程执行的时候其他想执行
synchronized代码块的线程就需要等待这个锁。我们把这种当只有一个线程可以访问的代码称为临界区,这种多线程模式称为Single
Thread Execution。
一般作为于方法和代码块:
public synchronized void method() {// TODO Auto-generated method stub}
synchronized(obj) {}
这时候锁住的是对象(方法所在的对象),于是当一个对象的 synchronized 代码有一个线程运行,其他线程也不能进入需要该对象其他代码块或方法。
还有一种是静态方法:
public static synchronized void method() {}
此时需持有对应类的class对象的锁。
java中另外一种锁是明锁:ReentrantLock。
比如上面的例子,pass方法改为:
private ReentrantLock lock = new ReentrantLock();public void pass(String name,String address) {// TODO Auto-generated method stublock.lock();this.count++;this.name = name;this.country = address;Check();lock.unlock();}
同样也是线程安全的。
相对来说,ReentrantLock更加安全,但是存在一些隐患。、
public void method() {lock.lock();if(条件){return;//或者抛异常}lock.unlock();}如果是进入if语句中,那么锁将永远打不开。那这一块代码其他线程就进不来了。安全的方式是在finally中解锁。
public void method() {lock.lock();try {if(条件){return;//或者抛异常}} finally{lock.unlock();}}
使用Single Thread Execution要注意的是避免死锁。死锁就是两个线程分别获得了锁定,互相等待另一个线程来解锁,最典型代码:
public void method1() {synchronized (A) {synchronized (B) {}}}public void method2() {synchronized (B) {synchronized (A) {}}}当一个线程调用了method1,另一个线程同时调用了method2,两个线程都出不来,都在等待对方持有的那把锁。
Single Thread Execution达到以下条件就会出现死锁:
1.具有多个锁参与其中。
2.线程锁定一个锁没解除就去获得其他锁。
3.线程获取这些锁的顺序不同。
以上条件只要打破一个就可以避免死锁发生。
- java多线程设计模式笔记之Single Thread Execution
- java多线程设计模式——学习笔记(2)Single Threaded Execution Pattern
- Single Threaded Execution----java多线程设计模式(一)
- 多线程模式之-single Threaded Execution Pattern
- 多线程设计模式(一) Single Threaded Execution
- Java多线程设计模式-学习笔记-Thread Per Message模式.
- java多线程设计模式之Thread-Per-Message模式
- Single Thread Execution
- Single Thread Execution
- Java多线程设计模式详解学习笔记九——Thread-Per-Message
- Java 多线程编程设计模式之 Thread Pool(线程池)
- java多线程设计模式笔记之Future Pattern
- java多线程设计模式笔记之Active Object
- Java中的线程(八)- Single Threaded Execution模式
- 《java多线程设计模式 第八章Worker Thread》
- java多线程设计模式Worker Thread(线程池)
- Java多线程Thread-并发协作(生产者消费者设计模式)
- 多线程之Thread--JAVA
- Codeforces Round #346 (Div. 2) F. Polycarp and Hay (并查集+bfs)★
- Codeforces 363B Fence-暴力
- 暑期社会实践心得
- 算法之最长公共子序列(LCS)算法
- 要说传统行业失业,其实程序员早就失业了,STEAMVR官网在哪里?
- java多线程设计模式笔记之Single Thread Execution
- IOS端AirWatch Agent配置文件
- ZooKeeper-3.3.4集群安装配置
- 苹果注册网页
- SQL Server JDBC 连接:sqljdbc4.jar sqljdbc_auth.dll配置与windows方式登录
- 由浅入深探究mysql索引结构原理、性能分析与优化
- linux命令英文缩写的含义(方便记忆)
- K近邻相关概念及其Python实现
- [Linux驱动入门]并发同步