Single Thread Execution 能通过这座桥的只有一个人

直奔主题, Single Thread Execution也称作Critical Section(临界区),范例如下:

public  class  SingleThreadGate {
     public  static  void  main(String[] args) {
         System. out .println( "ctrl + c to exit." );
         
         Gate gate = new  Gate();
         new  UserThread(gate, "Alice" , "Alaska" ).start();
         new  UserThread(gate, "Bobby" , "Brazil" ).start();
         new  UserThread(gate, "Chris" , "Canada" ).start();
     }
}
 
class  Gate{
     private  int  count;
     private  String name;
     private  String address;
     
     public  void  pass(String name, String address){
         this .count++;
         this .name=name;
         this .address=address;
         
         check();
     }
     
     public  void  check() {
         if  (name.charAt(0) != address.charAt(0)) {
             System. out .println( "*******BROKEN *******"  + toString());
         }
     }
 
     @Override
     public  String toString() {
         return  "No."  + count + " "  + name + ", "  + address;
     }
     
}
 
class  UserThread extends Thread{
     private  Gate gate;
     private  String name;
     private  String address;
     
     public  UserThread(Gate gate, String name, String address){
         this .gate=gate;
         this .name=name;
         this .address=address;
     }
 
     @Override
     public  void  run() {
         System. out .println(name+ ":begin->" );
         while ( true ){
             gate.pass(name,address);
             Thread.yield();
         }
     }
}

 

执行之后,会发现ou一很多broken,因为在执行pass的时候成员变量被其他线程改变了,所以判断name和address不一致,另外toString方法也存在同样的问题,执行过程中 name和address也随时被其他线程改变,所以会导致同一条记录的name和address也不一致,结果如下:

复制代码
ctrl + c to exit.
Alice:begin->
Chris:begin->
Bobby:begin->
*******BROKEN *******No.306 Bobby, Brazil
*******BROKEN *******No.487 Chris, Canada
*******BROKEN *******No.624 Bobby, Brazil
*******BROKEN *******No.6956 Bobby, Brazil
*******BROKEN *******No.7487 Alice, Canada
*******BROKEN *******No.7756 Chris, Alaska
*******BROKEN *******No.8010 Alice, Canada
*******BROKEN *******No.8288 Bobby, Brazil
*******BROKEN *******No.8550 Chris, Alaska
*******BROKEN *******No.8910 Bobby, Brazil
*******BROKEN *******No.9397 Chris, Alaska
*******BROKEN *******No.9715 Bobby, Brazil
复制代码

 

那么如何改进呢?将pass方法加上synchronized关键字,这样就不会有任何错误了。不过这还不能保证整个gate类的所有方法都是安全的,当调用toString方法时还是会有同样的name与address不一致的问题,所以在toString方法上也要加上synchronized关键字,那么check方法还需要么?答案是不需要,因为check方法时私有的,外部无法访问,而且check方法是被pass方法调用的,而pass方法已经同步了,一个类中的synchronized关键之都是锁定的同一对象(this),所以不需要二次锁定,浪费性能。

 synchnronized关键字也可以理解成把方法变成原子性操作,在java中,基本数据类型(primitive)如int, char, byte等都是原子性操作的,但是long和double则不一定,所以我们想把long和double这类非原子性类型按照原子性方式操作,需要加上关键字volatile,这样就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值