2013-11-25 100 views
1

嘿,我試圖把線程作爲一個概念。 讓我畫你一個場景線程何時共享對象? - Java

class A { 
    private int counter = 0; 

    public void add() { 
     counter++; 
    } 

    public int getCounter() { 
     return counter; 
    } 
} 

class B implements Runnable { 
    public void run() { 
     A a = new A(); 
     a.add(); 
     a.add(); 
    } 
} 

class C implements Runnable { 
    public void run() { 
     A a = new A(); 
     System.out.println(a.getCounter()); 
    } 
} 

什麼是System.out.println給我,當我運行C? 我猜它給了我0,因爲他們每個都創建了一個A的實例。

如果這是真的,你將如何分享線程之間的對象?

+2

請您正確格式化您的示例!它甚至沒有編譯。 – isnot2bad

回答

2

你不會在System.out上看到任何東西,因爲你沒有一個完整的程序。但是,假設你創建了兩個線程,並且運行了B,然後運行C與另一個,是的,0會被打印出來,因爲在你猜測的時候,每個線程都使用一個單獨的A實例。這很好,因爲A不會,沒有任何內存障礙可以讓它被多線程安全地訪問。

要共享數據,您需要將一個對象傳遞給兩個線程。例如:

final class Test { 

    public static void main(String[] argv) throws InterruptedException { 
    AtomicInteger shared = new AtomicInteger(); 
    Thread a = new B(shared).start(); 
    a.join(); 
    Thread b = new C(shared).start(); 
    b.join(); 
    } 

} 

final class B extends Thread { 

    private final AtomicInteger shared; 

    B(AtomicInteger shared) { this.shared = shared; } 

    @Override() 
    public void run() { 
    shared.getAndIncrement(); 
    shared.getAndIncrement(); 
    } 

} 

final class C extends Thread { 

    private final AtomicInteger shared; 

    C(AtomicInteger shared) { this.shared = shared; } 

    @Override() 
    public void run() { 
    System.out.println(shared.get()); 
    } 

} 

這將打印2,因爲主要方法是確保線程順序運行。在更現實的方法中,線程將同時啓動,並且根據相對時序打印0,1或2。

+0

對於我的代碼,我感到很遺憾,它的意思有點像僞代碼,我認爲它足夠清晰,我的意思是它。 但後來我正確理解,如果每個類創建一個對象,他們不會使用相同的int。 你說傳球的對象,有沒有其他的選擇? –

+0

謝謝你的回答我很清楚,但我想我會依靠atm的傳遞。 –

+0

@AllanPedersen重要的是線程之間共享的對象對於併發訪問必須是安全的。這意味着不僅應該對共享對象進行多重修改,而且還要確保內存屏障保證了其他線程可以看到更改。使用不可變對象或使用併發隊列在標識點處將對象從一個線程顯式傳遞到另一個線程是比較安全的,而不是讓任何一個對象在任何時候都可以異步修改。 – erickson

1

在控制檯中看到的東西(假設某些實例化C並將它傳遞給執行它的線程)將爲0,因爲沒有其他任何內容正在寫入該實例A.a是run方法的局部變量,沒有別的東西可以看到它。

多線程訪問是指對象在線程之間傳遞時。一個典型的例子是一個隊列,其中有不同的線程寫入數據結構,其他線程從相同的數據結構中刪除對象。 寫入隊列(生產者)的每個線程都會創建對象並將其放入隊列中。相同的對象將被不同的線程(稱爲消費者)檢索,這些線程致力於從隊列中取出對象並對它們執行某些操作。所以一個生產者創建的對象被放置在隊列中,並保持在那裏,直到被消費者佔用。

這是一個簡單的隊列實現。它使用​​鎖定內部列表,以便一次只有一個線程可以訪問隊列。

public class MyQueue<T> { 

    private List<T> list = new ArrayList<T>(); 

    public T take() throws InterruptedException { 
     synchronized(list) { 
      while (list.size() == 0) { 
       list.wait(); 
      } 
      return list.remove(0); 
     } 
    } 

    public void put(T object) { 
     synchronized(list) { 
      list.add(object); 
      list.notifyAll(); 
     } 
    } 
} 
+0

這應該是被接受的答案。隊列最可靠的是OP所指的。 – Chisx