多线程设计模式之(SingleThreadExecution)
要点:同一时刻只能一个线程访问共享资源
简述理解:独木桥、排它性,说白了就是加一个锁,让这个线程自己先搞定
这里自己看着教程仿着写了一个航空检票的案例(其实是有问题的),一开始是没有加锁的pass方法,想要获得一个线程不安全的运行效果,成功了,但没有完全成功,因为运行后并没有出现什么线程不安全的问题,先来看看:
/**
*
* 航空检查类
*/
public class FlightSecurity {
//pass方法:比较乘客登机码(boardPass)和身份证(id)的第一个字母
public boolean pass(FlightTourist flightTourist,int boardCard) {
//一个类型的小转换
Integer id=flightTourist.getId();
Integer boardPass=boardCard;
String idCard=id.toString();
String boardPass1=boardPass.toString();
//check开始
if(idCard.charAt(0)==boardPass1.charAt(0)){
System.out.println("检票号:"+boardPass1+"身份证:"+idCard+"的游客"+"通过");
return true;
}else if(idCard.charAt(0)!=boardPass1.charAt(0)){
throw new RuntimeException("首字母不同");
}
return false;
}
}
/**
* 乘客类
*/
public class FlightTourist {
//身份证
private int id;
FlightTourist(int id){
this.id=id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
/**
* 测试类
*/
public class Test extends Thread{
//成员变量方式:乘客类和航空安全类
private FlightSecurity flightSecurity;
private FlightTourist flightTourist;
private int boardCard;
//构造
Test(FlightTourist flightTourist,FlightSecurity flightSecurity,int boardCard){
this.flightSecurity=flightSecurity;
this.flightTourist=flightTourist;
this.boardCard=boardCard;
}
//线程
@Override
public void run() {
//加个while,乘客子子孙孙无穷匮也
while (true){
try {
TimeUnit.SECONDS.sleep(1);//为了更好的效果
} catch (InterruptedException e) {
e.printStackTrace();
}
flightSecurity.pass(flightTourist,boardCard);
}
}
public static void main(String[] args) {
FlightSecurity flightSecurity1=new FlightSecurity();//这里航空安全对象作为一个共享资源
FlightTourist flightTourist=new FlightTourist(1234);//设置不同的乘客作为一个线程
FlightTourist flightTourist1=new FlightTourist(234);
FlightTourist flightTourist2=new FlightTourist(41234);
FlightTourist flightTourist3=new FlightTourist(3234);
//这里设置的都是首字母相同的,为的就是能体现多线程的不安全问题
new Test(flightTourist,flightSecurity1,1234).start();
new Test(flightTourist1,flightSecurity1,2345).start();
new Test(flightTourist2,flightSecurity1,45657).start();
new Test(flightTourist3,flightSecurity1,38982).start();
}
}
运行结果我是等了10分钟后发现还是这样:
表明不存在多线程不安全问题,本刚学了线程的菜鸡后来仔细找了找,发现原来其实并没有一个共享资源的存在,其实只是共享了这个对象的方法,但是并没有到共享这个对象的一个成员变量(我把成员变量给弄到局部变量里去了),所以这个线程很安全。。。。有点和ThreadLocal一样,方法的局部变量变成了一个单机版的资源。。。
于是将这个局部变量设置成航空安全类对象的成员变量,如下:
于是两个变量终于可以成为线程间的共享资源了(反省了一下,应该是我对这个共享资源理解不够深刻导致的)。改变后的运行结果如下:
成功体现多线程不安全问题!(具体的分析其实挺好理解的:多个线程不断对共享资源的读写,如果没有一个读写的锁机制,那么必然产生牛头不对马嘴的错误)。
那么如何解决呢,给pass方法加个锁sychronized(如果将check包装成外部方法,调用到这里依旧算是锁起来的一部分):
public synchronized boolean pass(FlightTourist flightTourist,int boardCard)
运行结果如下:
线程安全,搞定!
感慨:加个锁就是这个SingleThreadExecution(莫名对这个Single有点悲哀,独木桥落寞的单身背影,唉)。