2014-02-20 52 views
2

我創建了3個線程訪問內部類MyInnerClassThreadsAroundInnerClasses外部類。多線程訪問內部類

 
package com.test; 

public class ThreadsAroundInnerClasses { 
    public static void main(String[] args) { 
     Thread t1 = new Thread(new MyThread(), "THREAD-1"); 
     Thread t2 = new Thread(new MyThread(), "THREAD-2"); 
     Thread t3 = new Thread(new MyThread(), "THREAD-3"); 
     t1.start(); 
     t2.start(); 
     t3.start(); 
    } 

    static class MyInnerClass { 
     static int counter = 0; 
     public void printIt(String threadName) { 
      System.out.println("I am inside inner class, counter value is " + ++counter + " and thread name is " + threadName); 
     } 
    } 
} 

class MyThread implements Runnable { 
    @Override 
    public void run() { 
     ThreadsAroundInnerClasses.MyInnerClass innerObj = new ThreadsAroundInnerClasses.MyInnerClass(); 
     innerObj.printIt(Thread.currentThread().getName()); 
    } 
} 

在輸出中我可以看到,在MyInnerClasscounter靜態變量不按順序得到更新。

 
I am inside inner class, counter value is 1 and thread name is THREAD-1 
I am inside inner class, counter value is 3 and thread name is THREAD-2 
I am inside inner class, counter value is 2 and thread name is THREAD-3 

這將是很大的幫助,如果有人可以解釋類如何在內部多線程的情況下處理?我們可以同步整個內部課堂嗎?

在此先感謝您的幫助。

回答

1

試試這個:

static class MyInnerClass { 
    static int counter = 0; 
    public void printIt(String threadName) { 
     synchronized(MyInnerClass.class) { 
      System.out.println("I am inside inner class, counter value is " + ++counter + " and thread name is " + threadName); 
     } 
    } 
} 

你的計數器是靜態的,所以你需要全班對象上同步。

3

該類是否爲內部類是無關緊要的。你在這裏看到的是預期的輸出:你的程序中沒有任何同步,並且線程調度程序因此可以隨意切換到其他線程。這裏有一系列可能的操作,這會導致你看到的輸出。

  1. T1:遞增計數器
  2. T1:concaenate
  3. T1:打印
  4. T3:遞增計數器
  5. T3:串接
  6. T2:遞增計數器
  7. T2:串聯
  8. T2:打印
  9. T3 :打印

如果你想在櫃檯遞增,串聯和打印是一個原子操作,那麼你應該確保它是一個獨特的鎖同步:

synchronized MyInnerClass.class { 
    System.out.println("I am inside inner class, counter value is " + ++counter + " and thread name is " + threadName); 
} 
1

這是一個問題讀那麼改變線程的知名度和

讀那麼變化

的增量是先讀,然後添加,然後回寫。 ++countercounter = counter + 1的簡稱,這意味着:「讀取計數器,加一個,將結果寫回計數器」。這個流程可以在另一個線程的中間被中斷:Thread1讀取計數器,得到1 - 並被中斷。線程2讀取計數器 - 它仍然是1 - 增加1 - 並被中斷。線程3讀取計數器 - 它仍然是1 - ....等等。行爲基本上是隨機的。只需在後臺運行其他應用程序,您可能會激發不同的輸出。

螺紋能見度

有關多核架構的非易失性的,非同步的變量,不同的線程可以在不同的核心上運行,以及芯可以緩存在其寄存器中的變量。這意味着一個線程可能無法看到另一個線程寫入該變量 - 直到它被提交回內存並且有新的寫入。

同步是創建內存障礙的一種方式。系統將保證寫入的所有內容在內,鎖定在下一次鎖定時可見。實際上 - 當你的退出這個synchronized塊時,你所做的每件事都會被記錄下來。然後你輸入的同步塊,一切都從內存中讀回來。

volatile關鍵字告訴系統禁止將變量緩存在寄存器中 - 它必須始終在內存中讀寫。這使得每個人都閱讀到最新的內容,但由於上述原因,這並不能解決您的問題。

最簡單的辦法

解決您的特定問題的最簡單方法是使用的AtomicInteger。

static class MyInnerClass { 
    static final AtomicInteger counter = new AtomicInteger(0); 
    public void printIt(String threadName) { 
     System.out.println("I am inside inner class, counter value is " + 
      counter.incrementAndGet() + " and thread name is " + threadName); 
    } 
} 

這會爲您節省所有同步的麻煩 - 它包含在AtomicInteger類中。