Java 机场安检
chengqiuming 人气:0一 场景描述
乘飞机时,在进入登机口之前必须经过安全检查,安检口类似于独木桥,每次只能通过一个人,工作人员除了检查你的登机牌外,还有一些其它检查。在此模拟一个非线程安全的安检口类,旅客(线程)分别手持登机牌和SFZ接受工作人员的检查。
二 实战
1 FlightSecurity
package concurrent.FlightSecurity; public class FlightSecurity { private int count; // 登机牌 private String boardingPass = "null"; // SFZ private String idCard = "null"; public void pass(String boardingPass,String idCard){ this.boardingPass = boardingPass; this.idCard = idCard; this.count++; check(); } private void check() { // 简单测试,当登机牌和SFZ首字母不相同时则表示检查不通过 if(boardingPass.charAt(0)!=idCard.charAt(0)){ throw new RuntimeException("======Excepton======"+toString()); } } public String toString(){ return "The " +count +" paaaenges,boardingPass [" + boardingPass + "],idCard [" + idCard +"]"; } }
2 FightSecurityTest
package concurrent.FlightSecurity; public class FightSecurityTest { // 旅客线程 static class Passengers extends Thread{ // 机场安检类 private final FlightSecurity fightSecurity; // 旅客的SFZ private final String idCard; // 旅客登机牌 private final String boardingPass; Passengers(FlightSecurity fightSecurity, String idCard, String boardingPass) { this.fightSecurity = fightSecurity; this.idCard = idCard; this.boardingPass = boardingPass; } @Override public void run() { while(true){ // 旅客不断地过安检 fightSecurity.pass(boardingPass,idCard); } } } public static void main(String[] args) { // 定义三个旅客,SFZ和登机牌首字母相同 final FlightSecurity flightSecurity= new FlightSecurity(); new Passengers(flightSecurity,"A","A").start(); new Passengers(flightSecurity,"B","B").start(); new Passengers(flightSecurity,"C","C").start(); } }
三 测试
1 测试结果1
Exception in thread "Thread-1" Exception in thread "Thread-0" java.lang.RuntimeException: ======Excepton======The 356 paaaenges,boardingPass [B],idCard [A]
at concurrent.FlightSecurity.FlightSecurity.check(FlightSecurity.java:20)
at concurrent.FlightSecurity.FlightSecurity.pass(FlightSecurity.java:14)
at concurrent.FlightSecurity.FightSecurityTest$Passengers.run(FightSecurityTest.java:24)
java.lang.RuntimeException: ======Excepton======The 356 paaaenges,boardingPass [B],idCard [A]
at concurrent.FlightSecurity.FlightSecurity.check(FlightSecurity.java:20)
at concurrent.FlightSecurity.FlightSecurity.pass(FlightSecurity.java:14)
at concurrent.FlightSecurity.FightSecurityTest$Passengers.run(FightSecurityTest.java:24)
2 测试结果2
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.RuntimeException: ======Excepton======The 953 paaaenges,boardingPass [C],idCard [C]
at concurrent.FlightSecurity.FlightSecurity.check(FlightSecurity.java:20)
at concurrent.FlightSecurity.FlightSecurity.pass(FlightSecurity.java:14)
at concurrent.FlightSecurity.FightSecurityTest$Passengers.run(FightSecurityTest.java:24)
java.lang.RuntimeException: ======Excepton======The 1039 paaaenges,boardingPass [C],idCard [C]
at concurrent.FlightSecurity.FlightSecurity.check(FlightSecurity.java:20)
at concurrent.FlightSecurity.FlightSecurity.pass(FlightSecurity.java:14)
at concurrent.FlightSecurity.FightSecurityTest$Passengers.run(FightSecurityTest.java:24)
四 问题分析
在多线程情况下调用 pass 方法,虽然参数的传递百分百保证就是这两个值,但是在 pass 方法中对这两个值的赋值很有可能交叉,不能保证原子性操作。
解决的方法是给 pass 方法加上 synchronized 关键字。
public synchronized void pass(String boardingPass,String idCard)
五 说明
在 Java 中经常会听到线程安全的类和线程非安全的类,所谓线程安全的类是指多个线程同时进行操作时,不会引起数据不一致问题,反之则是线程非安全的类,在线程安全的类中经常会看到 synchronized 关键字的身影。
加载全部内容