这里有一座独木桥。因为桥身非常的细,一次只能允许一个人通过。当这个人没有下桥,另一个人就不能过桥。如果桥上同时又两个人,桥就会因为无法承重而破碎而掉落河里。 这就是Single Threaded Execution。有时也称为Critical section(临界区)。
这个模式用来限制同时只允许一个线程运行。
机场过安检
1.非线程安全
代码:
package com.zl.step16.flight;
public class FlightSecurity {
private int count = 0 ;
// 登机牌
private String boardingPass = "null" ;
// 身份证
private String idCard = "null" ;
// 通过安检信息
public void pass(String boardingPass , String idCard){
this.boardingPass = boardingPass ;
this.idCard = idCard ;
this.count ++;
check();
}
// 安全检查
private void check() {
// 简单测试,当登机牌和身份证首字母不相同时,则表示检查不通过 仅为测试,别较真。。。。
if(boardingPass.charAt(0) != idCard.charAt(0)){
throw new RuntimeException("=====Exeception============"+ toString()) ;
}
}
@Override
public String toString() {
return "The" + count+ " passengers , boardingPass["+boardingPass+"] , idCard ["+idCard+"]。";
}
}
package com.zl.step16.flight;
public class FlightSecurityTest {
static class Passengers extends Thread{
private final FlightSecurity flightSecurity ;
// 身份证
private final String idCard ;
// 登机牌
private final String boardingPass ;
// 构造旅客对象
public Passengers(FlightSecurity flightSecurity , String idCard ,String boardingPass){
this.flightSecurity = flightSecurity ;
this.idCard = idCard ;
this.boardingPass = boardingPass ;
}
@Override
public void run(){
while (true){
// 不断通过安检
flightSecurity.pass(boardingPass,idCard);
}
}
}
public static void main(String[] args) {
final FlightSecurity flightSecurity = new FlightSecurity() ;
new Passengers(flightSecurity,"A11","A21").start();
new Passengers(flightSecurity,"B12","B22").start();
new Passengers(flightSecurity,"B13","B23").start();
}
}
异常信息:
问题分析:
1.首字母相同,却无法通过安检
2.首字母不同现象:
线程安全:
修改pass方法: 增加 synchronized 关键字即可
什么时候适合Single Thread Execution设计模式
1.多线程访问资源的时候,被synchronized同步的方法总是排他性的。
2.多个线程对某个类的状态发生改变的时候
吃面问题:
演示交叉锁导致程序死锁的情况:
package com.zl.step16.noodle;
public class Tableware {
//餐具名称
private final String toolName ;
public Tableware(String toolName){
this.toolName= toolName ;
}
@Override
public String toString(){
return "Tool: "+toolName ;
}
}
package com.zl.step16.noodle;
public class EatNoodleThread extends Thread {
private final String name ;
//左手边的餐具
private final Tableware leftTool ;
private final Tableware rightTool ;
public EatNoodleThread(String name ,Tableware leftTool , Tableware rightTool ){
this.name = name ;
this.leftTool = leftTool ;
this.rightTool = rightTool ;
}
@Override
public void run(){
while (true){
this.eat();
}
}
private void eat() {
synchronized (leftTool){
System.out.println(name + "take up "+ leftTool +" (left)" );
synchronized (rightTool){
System.out.println(name + "take up "+ rightTool +" (right)" );
System.out.println(name + "is eating now." );
System.out.println(name + "put down "+rightTool +" (right)" );
}
System.out.println(name + "put down "+rightTool +" (left)" );
}
}
}
package com.zl.step16.noodle;
public class EatNoodleThreadTest {
public static void main(String[] args) {
Tableware fork = new Tableware("fork") ;
Tableware knife = new Tableware("knife") ;
new EatNoodleThread("A" , fork ,knife).start();
new EatNoodleThread("B" , fork ,knife).start();
new EatNoodleThread("C" , fork ,knife).start();
new EatNoodleThread("D" , fork ,knife).start();
new EatNoodleThread("E" , fork ,knife).start();
}
}
解决:
主要问题:交叉锁导致两个线程之间互相等待彼此释放持有的锁。
代码:
package com.zl.step16.noodle;
public class Tableware {
//餐具名称
private final String toolName ;
public Tableware(String toolName){
this.toolName= toolName ;
}
@Override
public String toString(){
return "Tool: "+toolName ;
}
}
package com.zl.step16.noodle;
public class TableWarePair {
//左手边的餐具
private final Tableware leftTool ;
private final Tableware rightTool ;
public TableWarePair( Tableware leftTool , Tableware rightTool ){
this.leftTool = leftTool ;
this.rightTool = rightTool ;
}
public Tableware getLeftTool() {
return leftTool;
}
public Tableware getRightTool() {
return rightTool;
}
}
package com.zl.step16.noodle;
public class EatNoodleThread extends Thread {
private final String name ;
private final TableWarePair tableWarePair ;
public EatNoodleThread(String name , TableWarePair tableWarePair ){
this.name = name ;
this.tableWarePair = tableWarePair ;
}
@Override
public void run(){
while (true){
this.eat();
}
}
private void eat() {
synchronized (tableWarePair){
System.out.println(currentThread().getName() + " : " + name + " take up "+ tableWarePair.getLeftTool() +" (left)" );
System.out.println(currentThread().getName() + " : " + name + " take up "+ tableWarePair.getRightTool() +" (right)" );
System.out.println(currentThread().getName() + " : " + name + " is eating now." );
System.out.println(currentThread().getName() + " : " + name + " put down "+tableWarePair.getRightTool() +" (right)" );
System.out.println(currentThread().getName() + " : " + name + " put down "+tableWarePair.getLeftTool() +" (left)" );
}
}
}
package com.zl.step16.noodle;
public class EatNoodleThreadTest {
public static void main(String[] args) {
Tableware fork = new Tableware("fork") ;
Tableware knife = new Tableware("knife") ;
TableWarePair tableWarePair = new TableWarePair(fork,knife) ;
new EatNoodleThread("A" , tableWarePair).start();
new EatNoodleThread("B" , tableWarePair).start();
}
}