从一篇Blog看两个并发编程错误

来源:互联网 发布:json new date 格式化 编辑:程序博客网 时间:2024/04/29 02:13

发现公司支付宝接入的代码有点神奇,在网上搜索了下,找到原始版本。估计有不少人都是抄那份代码的。

原文在:http://blog.csdn.net/simdanfeg/article/details/9011603    Android支付接入(一):支付宝

但是代码里有两个明显的并发问题,尽管在Android下可能不会有问题。

下面摘抄一段:

    public class MobileSecurePayer {          <strong>Integer lock = 0;  </strong>          // 和安全支付服务建立连接          private ServiceConnection mAlixPayConnection = new ServiceConnection (){              public void onServiceConnected (ComponentName className, IBinder service){                  //                  // wake up the binder to continue.                  // 获得通信通道                  <strong>synchronized (lock)</strong>{                      mAlixPay = IAlixPay.Stub.asInterface (service);                      lock.notify ();                  }              }              // 实例一个线程来进行支付              new Thread (new Runnable (){                  public void run (){                      try{                          // wait for the service bind operation to completely                          // finished.                          // Note: this is important,otherwise the next mAlixPay.Pay()                          // will fail.                          // 等待安全支付服务绑定操作结束                          // 注意:这里很重要,否则mAlixPay.Pay()方法会失败                          synchronized (lock){   <strong>                           if (mAlixPay == null)                                  lock.wait (); </strong>                         }  

第一个问题:用Integer做lock对象。

在Oracle JDK里,Integer是有会缓存的,从-128 到127的Integer会缓存到内部的一个IntegerCache,所以两个Integer可能会是同一个对象。还可以用-XX:AutoBoxCacheMax参数来设置cache的范围。

另外,即使Integer的内部实现是没有缓存的,对于像Integer lock = 0; 这样的代码,编绎器可能会把它变成一个变量,然后共享这样一个常量。

所以可能不同的类,会共享了一个synchronized (lock)对象,线程的并发度大大降低,甚至可能会有死锁。

同理,像Boolean,Float,Long这种类型都是不适合用来做lock对象的。

最好的办法是直接 Object lock = new Object(); 。


第二个问题:wait方法没有在while循环里。

绝大部分情况下,object.wait()方法都应该while循环来判断条件变量。因为wait()函数可能会因为spurious wakeup而返回。

spurious wakeup请参考另一篇blog:http://blog.csdn.net/hengyunabc/article/details/27969613

另外直接看JDK的文档,里面就说得很清楚:

//As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:      synchronized (obj) {         while (<condition does not hold>)             obj.wait();         ... // Perform action appropriate to condition     }

最后,支付宝的接入应该去官方的网站找文档。不过这网站不好找,在支付宝的主页貌似没有链接过去。。

https://openhome.alipay.com/doc/docIndex.htm

1 0
原创粉丝点击