2012-07-27 43 views
1

在閱讀線程安全時,我遇到了這個問題。 如果我是正確的方法本地基本體和對象引用生活在一個堆棧內,並且堆棧內引用指向的實際對象位於堆中。方法局部變量和堆棧和堆

但是,當涉及到方法本地非原始對象初始化,會不會導致併發問題?我的意思是如果方法locals非基元生活在堆中,只有指針存在於堆棧中,是不是與實例變量相同?

有人可以幫我瞭解這個....

PS兩個線程

覺得跟每個都具有自己的兩個堆棧和一個堆。我所理解的是這兩個線程將它們的方法本地原始變量保存在其堆棧中。我沒有這個問題。

但是如果我們有一個非原始方法局部變量的方法呢?然後,如果該變量的對象存儲在堆內部,那麼這兩個線程將有權訪問同一對象,對嗎?所以如果是這樣的話會有同步問題。

這就是我要問的。

感謝

+0

您想象的是什麼類型的併發問題? – 2012-07-27 06:36:07

+0

沒有特定的。只是想知道如果我在上面的問題中是正確的話線程處理非原始對象。 – 2012-07-27 06:42:33

+0

我看不出線程與此有關。你對你的擔憂並不十分清楚。 – 2012-07-27 06:44:11

回答

1

如果兩個線程都有對該對象的引用,則它們可以訪問同一個對象。如果您有類似下面的方法:

public String concat(String a, String b) { 
    StringBuilder builder = new StringBuilder(); 
    builder.append(a); 
    builder.append(b); 
    return builder.toString(); 
} 

StringBuilder對象確實是在堆,但只有一個線程擁有這個對象的引用。沒有其他線程可以引用此StringBuilder。所以它本質上是線程安全的。

如果相反,則有以下:

public String concat(String a, String b) { 
    final StringBuilder builder = new StringBuilder(); 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      builder.append("haha!"); 
     } 
    }).start(); 
    builder.append(a); 
    builder.append(b); 
    return builder.toString(); 
} 

然後你有一個線程安全的問題,因爲你希爾與另一個線程本地創建的對象的引用,而StringBuilder的是不是線程安全的。

+0

引用代碼片段的第一部分,是否意味着堆中會有多個** builder **對象的副本? (每個線程一個) – 2012-07-27 07:16:33

+0

是的,當然。當你執行'new SomeObject()'時,你創建了'SomeObject'的一個** new **實例。 – 2012-07-27 07:18:09

+0

再次感謝,爲什麼不保持方法本地非原始內部的堆棧? – 2012-07-27 07:29:19

0

局部變量或者是原語,以創建別處對象的引用(如果你做一個分配),或到新創建的對象的引用(用「新」運算符)

對於第一種情況如你所說,沒有問題。

對於最後一種情況,因爲你是在本地craeting一個新的對象,新對象將在每次調用創建的,所以沒有併發問題,因爲將有堆一個對象每次調用

但對於第二種情況,因爲對象已經創建在其他地方,所以你必須考慮併發性

2

但是如果我們有一個非原始方法局部變量的方法 ?然後,如果該變量的對象存儲在堆內,那麼這兩個線程將有權訪問同一對象,對嗎?所以 如果是這樣的話會有同步問題。

我想知道爲什麼你會認爲這兩個引用會引用同一個對象。

提到對象的創建是明確新的做(或其他類似方法,但思路是一樣的)

因此,與在C++中,如果你是在Java中

Foo foo; 
宣稱這

沒有Foo對象實例化。 foo只是一個指向什麼都沒有的指針。

這會在堆中創建一個Foo對象實例。

Foo foo = new Foo(); 

如果兩個線程正在運行該代碼段,線程1將在堆疊中的Foo參考,並要求分配在堆一個新Foo對象,然後將該Foo obj的地址分配給所述參考foo。線程2也是這樣做的。請注意,線程2也要求分配一個新的Foo對象,它將成爲線程1分配的不同對象。

這是基本的(而且非常簡化)的想法。

0

只是爲了折騰我的想法,可能是你的困惑點:堆沒有像堆棧一樣管理。它是共享的,是的 - 所有線程創建的對象都在堆中。然而,由於每個對象是創建的,它在堆中被賦予一個唯一的位置/空間。兩個線程同時運行並創建對象實例的兩種方法將在共享堆中創建明顯不同的對象。

它們在此共享堆中創建,因此如果方法foo返回對象引用或存儲它,或調用另一個間接存儲它的方法...... foo返回並且堆棧爲彈出。

有一個垃圾收集器的魔力是,你不必跟蹤這個「東西」,並在未來某個適當的時候自己摧毀它。保持代碼簡單,讓您專注於算法(或學習編程)。但是,我離題...

1

But what if we have a method with non primitive method local variables ? Then if the object for that variable is stored inside the heap, both the threads will have the access to the same object, won't they ? So if that's the case there would be Sync problems

您部分回答了你自己question.That參考值存儲在堆棧,但實際的對象內容存儲在堆中,當你調用新的對象()每個線程創建不同的新對象將存儲在堆中,並且每個線程使用存儲在其自己的堆棧中的參考值訪問其創建的對象