2017-10-17 58 views
0

为什么value设置正确,即使我们在不同的线程中使用不同的锁?即使我们在不同的线程中使用不同的锁,为什么值设置正确

public class MyThread implements Runnable { 
    static String a = "LOCK"; 
    static String b = "LOCK"; 
    int id; 
    static int value = 0; 

    MyThread(int id) { 
     this.id = id; 
    } 

    @Override 
    public void run() { 
     if (id == 0) { 
      synchronized (a) { 
       for (int i = 0; i < Main.N; i++) 
        value = value + 3; 
      } 
     } else { 
      synchronized (b) { 
       for (int i = 0; i < Main.N; i++) 
        value = value + 3; 
      } 
     } 
    } 
} 

public class Main { 
    static final int N = 100000; 
    static int ITER = 100; 

    public static void main(String[] args) { 
     Thread threads[] = new Thread[2]; 
     boolean sw = true; 
     for (int j = 0; j < ITER; j++) { 
      MyThread.value = 0; 
      for (int i = 0; i < 2; i++) 
       threads[i] = new Thread(new MyThread(i)); 
      for (int i = 0; i < 2; i++) 
       threads[i].start(); 
      for (int i = 0; i < 2; i++) { 
       try { 
        threads[i].join(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      if (MyThread.value != 2 * 3 * N) { 
       System.out.println("i was different than " + 2 * 3 * N + ", it is " + MyThread.value); 
       sw = false; 
      } 
     } 
     if (sw) 
      System.out.println("Something is strange"); 
    } 
} 
+2

为什么你认为一个线程安全错误会保证显示出来?实际上,线程安全错误的定义是,他们可以在没有的情况下正常工作。 –

+0

一个*可能的原因是第一个线程在第二个线程开始之前完成。 –

+1

@jack你需要上下文的调用代码。没有它,答案可能是“因为线程一个接一个地运行”。 –

回答

3

为了节省内存,Java字符串会被执行。

您的两个"LOCK"字符串(因此您锁定的两个对象)实际上是同一个对象。

这是(原因之一)为什么你永远不应该锁定原语。

+0

我很盲目:( – jack

+0

至少,对于同步对象来说,'new Object()'是最好的选择,尽管投入时间学习java.util.concurrent.locks是绝对要分红! – corsiKa

3

切勿使用String如锁,因为很可能是因为字符串池中的其他String的同一个实例。

就你而言,你的两个"LOCK"字符串实际上是同一个对象。

+0

第一句是一般情况:2'String' - 具有相同的内容 - * *可以是相同的对象,如果它们都被*实现了*因此不应该被用作锁。 –

相关问题