2016-01-09 49 views
3

我在閱讀Oracle提供的官方Java Tutorial,我想將我的知識付諸實踐。如何在java中使用內部鎖?

我想看Thread Interference的行動和使用Intrinsic Locks and Synchronization解決它。所以,我創建了一個名爲Counter的類:

  • 兩個字段都被初始化爲0
  • 方法遞增和遞減它們的值。
  • 打印出值的方法。

public class Apple { 
    public static void main(String[] args) { 
     Counter myCounter = new Counter(); 
     Thread a = new Thread(myCounter); 
     Thread b = new Thread(myCounter); 

     a.start(); 
     b.start(); 
    } 
} 

class Counter implements Runnable { 
    public int a = 0; 
    public int b = 0; 

    void incA() { 
     ++a; 
    } 

    void decA() { 
     --a; 
    } 

    void incB() { 
     ++b; 
    } 

    void decB() { 
     --b; 
    } 

    void printValues() { 
     System.out.println("a: " + a + " | b: " + b); 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      incA(); 
      decA(); 
      incB(); 
      decB(); 
      printValues(); 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

首先,我運行我的程序時未使用內部鎖或同步,輸出是我期望的線程干擾。

... 
a: 0 | b: 0 
a: 0 | b: 1 
a: 0 | b: 0 
a: 1 | b: 0 
a: 0 | b: 0 
... 

現在我想整理使用內部鎖定此問題,以便當一個線程遞增或遞減一個,另一個線程可以在同一時間改變B,而不是使用synchronized方法這將阻止。

所以我使用內部鎖添加了兩個新字段(鎖)和同步塊。這裏是新的代碼:

class Counter implements Runnable { 
    public int a = 0; 
    public int b = 0; 
    Object lock1 = new Object(); 
    Object lock2 = new Object(); 

    void incA() { 
     synchronized (lock1) { 
      ++a; 
     } 
    } 

    void decA() { 
     synchronized (lock1) { 
      --a; 
     } 
    } 

    void incB() { 
     synchronized (lock2) { 
      ++b; 
     } 
    } 

    void decB() { 
     synchronized (lock2) { 
      --b; 
     } 
    } 

    void printValues() { 
     System.out.println("a: " + a + " | b: " + b); 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      incA(); 
      decA(); 
      incB(); 
      decB(); 
      printValues(); 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

我沒有做任何改變的主要方法,所以我沒有包括它。但是我跑這個代碼三次,這是最後一次嘗試輸出:

... 
a: 0 | b: 0 
a: 0 | b: 0 
a: 0 | b: 1 
a: 0 | b: 0 

我做了什麼錯?代碼應該如何?

我只是想要一個簡單的示例代碼,使用內部鎖。

+0

你的輸出有什麼問題?對我來說它看起來正確。 –

+0

另外爲什麼你需要'myCounter.printValues();'在你的主要方法? – theo

+0

@theo對不起,我從以前的嘗試離開它。 –

回答

4

printValues()讀取並打印值,而另一個線程增加或減少值:它不同步。即使是這樣,它也可以在另一個線程的調用incB()decB()之間讀取和打印b

所以可以有

  • 線程1倍的增量乙 - > B = 1個
  • 線程2讀取並打印乙 - > b的打印爲1
  • 線程1個遞減b - > b = 0

如果沒有人曾經應該看到b處從0開始,然後incB();decB()應該是單一的原子操作,通過將在一個單一的同步塊這兩個調用,和b的讀出也應b Ë放入同步塊,使用同一把鎖:

class Counter implements Runnable { 
    private int a = 0; 
    private int b = 0; 
    private final Object lock1 = new Object(); 
    private final Object lock2 = new Object(); 

    private void incA() { 
     ++a; 
    } 

    private void decA() { 
     --a; 
    } 

    private void incB() { 
     ++b; 
    } 

    private void decB() { 
     --b; 
    } 

    private void printValues() { 
     System.out.println("a: " + a + " | b: " + b); 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      synchronized (lock1) { 
       incA(); 
       decA(); 
      } 

      synchronized (lock2) { 
       incB(); 
       decB(); 
      } 

      synchronized (lock1) { 
       synchronized (lock2) { 
        printValues(); 
       } 
      } 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
+0

謝謝!有效。 –

1

你怎麼樣從run()方法和在你的主線程你等待所有的線程在打印之前完成刪除printValues()?所以主要是:

public static void main(String[] args) throws InterruptedException { 
Counter myCounter = new Counter(); 
Thread a = new Thread(myCounter); 
Thread b = new Thread(myCounter); 

a.start(); 
b.start(); 

a.join(); 
b.join(); 
myCounter.printValues(); 
}