zoukankan      html  css  js  c++  java
  • 对象锁 乱同步

    转自http://rednaxelafx.iteye.com/blog/551715

    昨天在用findbugs扫我们的代码时看到了类似这样的bug提示:(嗯……真的方法名忽略吧) 

    findbugs 写道
    Bug: alpha.beta.charlie.Foo.bar(String) calls Thread.sleep() with a lock held 
    Pattern id: SWL_SLEEP_WITH_LOCK_HELD, type: SWL, category: MT_CORRECTNESS 

    This method calls Thread.sleep() with a lock held. This may result in very poor performance and scalability, or a deadlock, since other threads may be waiting to acquire the lock. It is a much better idea to call wait() on the lock, which releases the lock and allows other threads to run.



    那段代码看起来与下面的Foo.bar()类似: 

    Java代码  收藏代码
    1. public class TestSync {  
    2.   public static void main(String[] args) throws Exception {  
    3.     Foo foo = new Foo();  
    4.     Thread t1 = new Thread(new MyRunnable(foo));  
    5.     Thread t2 = new Thread(new MyRunnable(foo));  
    6.     t1.start();  
    7.     t2.start();  
    8.   }  
    9. }  
    10.   
    11. class MyRunnable implements Runnable {  
    12.   private Foo foo;  
    13.     
    14.   public MyRunnable(Foo foo) {  
    15.     this.foo = foo;  
    16.   }  
    17.     
    18.   public void run() {  
    19.     foo.bar("alpha");  
    20.   }  
    21. }  
    22.   
    23. class Foo {  
    24.   public void bar(String name) {  
    25.     String key = name + "_"; // this will create a new "key" object every time invoked  
    26.     synchronized (key) {  
    27.       try {  
    28.         System.out.println("1: " + name);  
    29.         Thread.sleep(1000);  
    30.         System.out.println("2: " + name);  
    31.         Thread.sleep(5000);  
    32.       } catch (InterruptedException e) {  
    33.         System.err.println("interrupted");  
    34.       }  
    35.     }  
    36.   }  
    37. }  


    可以看到输出经常是: 

    1: alpha
    1: alpha
    2: alpha
    2: alpha


    嗯,在synchronized块里用了Thread.sleep(),是很邪恶。正准备看看有没有什么办法去修一下,突然发现更糟糕的问题是那synchronized块完全是废的:每次Foo.bar()被调用的时候,“key”都是一个新生成的String对象;于是锁住的根本不是同一个对象,实际上没达到锁的目的。 

    如果把“+”去掉,并且确保输入的参数是指向同一个String对象(Java里字符串字面量由VM保证会被intern),再看程序的行为就很不同了: 

    Java代码 
    1. public class TestSync {  
    2.   public static void main(String[] args) throws Exception {  
    3.     Foo foo = new Foo();  
    4.     Thread t1 = new Thread(new MyRunnable(foo));  
    5.     Thread t2 = new Thread(new MyRunnable(foo));  
    6.     t1.start();  
    7.     t2.start();  
    8.   }  
    9. }  
    10.   
    11. class MyRunnable implements Runnable {  
    12.   private Foo foo;  
    13.     
    14.   public MyRunnable(Foo foo) {  
    15.     this.foo = foo;  
    16.   }  
    17.     
    18.   public void run() {  
    19.     foo.bar("alpha");  
    20.   }  
    21. }  
    22.   
    23. class Foo {  
    24.   public void bar(String name) {  
    25.     String key = name; // notice this doesn't create a new object  
    26.     synchronized (key) {  
    27.       try {  
    28.         System.out.println("1: " + name);  
    29.         Thread.sleep(1000);  
    30.         System.out.println("2: " + name);  
    31.         Thread.sleep(5000);  
    32.       } catch (InterruptedException e) {  
    33.         System.err.println("interrupted");  
    34.       }  
    35.     }  
    36.   }  
    37. }  


    输出总是: 

    1: alpha
    2: alpha
    1: alpha
    2: alpha



    然而String这东西,普遍来说在运行时即便equals也无法保证是“同一对象”,所以这代码本身的设计就很有问题,不光是在Thread.sleep()上了。 

    诶,生产力就消磨在起JBoss,看错误log,关JBoss刷Maven,改代码,刷Maven来build然后再起JBoss……而且遗留下来的问题各种诡异。findbugs默认抓的虫也还不够多 =_=|||| =o) TvT||||

  • 相关阅读:
    git
    Ubuntu编写makefile文件编译时显示makefile:2: *** missing separator. Stop.”,修改tab键后仍报相同的错
    cd /root/ 权限不够
    bash: ./arm-none-linux-gnueabi-gcc: No such file or directory
    安装Linux的交叉编译工具链
    DNW刷机步骤
    dnw刷机时刷不进去,进度条不动
    【Redis】基本数据类型常用操作
    【Redis】基本数据类型常用操作
    【Redis】基本数据类型常用操作
  • 原文地址:https://www.cnblogs.com/leihupqrst/p/4047986.html
Copyright © 2011-2022 走看看