《java concurrency in practice》中有一段代碼如下:
class HolderPlace{
public Holder holder;
public void initHolder(){
holder = new Holder(42);
}
}
class Holder{
private int n;
public Holder(int n) {
this.n = n;
}
public void assertSanity(){
if(n!=n){
throw new AssertionError("....Assertion error...");
}
}
}
理論上呢,也能看懂為啥線程不安全,比如如果是下邊的操作:執(zhí)行HolderPlacer.holder.assertSanity的(n!=n) 的第一個n時Holder還沒給n賦值呢,但是等到第二個n執(zhí)行完值給賦上了,就導致了(n!=n)==true
HolderPlace place = new HolderPlace();
new Thread(()->place.initHolder()).start();
new Thread(()->{
try{
place.holder.assertSanity();
}catch (NullPointerException e){
}
}).start();
但是我想讓這個bug出現(xiàn),應該怎么做才能提高bug出現(xiàn)的概率?總不能光讓我憑理論分析。
感謝回答者
@@@@@@@@@@@@@@@@@@編輯分割線 。。。剛才給添加到評論里了@@@@@@@@@@@@@@@@
怕大家走偏了,
我是想證明真的存在“雖然構(gòu)造函數(shù)已經(jīng)執(zhí)行完成,引用也指向了這個對象,但是,這個對象的非final域可能還未真正的賦值”
再舉個例子如下:
public class Tx {
public int n;
public Tx(int n) {
this.n = n;
}
}
public class Cons {
public static final int INIT_NUM = 100;
public static void main(String[] args) {
for(int i=0;i<10000;i++){
Map m = new HashMap<>();
new Thread(()->{m.put("a",new Tx(INIT_NUM));}).start();
new Thread(()->{
try {
Assert.assertEquals(INIT_NUM,((Tx)m.get("a")).n);
}catch (NullPointerException e){
//do nothing
}
}).start();
}
}
}
但是這段代碼我仍然跑不出來異常。。。。(或者有沒有人能提供能證明這個問題的例子,還要能跑出結(jié)果來。。。
4 回答

慕的地8271018
TA貢獻1796條經(jīng)驗 獲得超4個贊
應該不會重現(xiàn)的,因為這段會被編譯器優(yōu)化掉:
public void assertSanity() {
if (n != n) {
throw new AssertionError("....Assertion error...");
}
}
可能優(yōu)化成:
public void assertSanity() {
if (false) {
throw new AssertionError("....Assertion error...");
}
}
甚至是:
public void assertSanity() {
// Do Nothing
}

慕容森
TA貢獻1853條經(jīng)驗 獲得超18個贊
你要重現(xiàn)以證明BUG的存在,沒必要真的跑,你只要使用多線程的Debug模式,控制兩個線程的執(zhí)行步調(diào),就可以重現(xiàn)。而真正線程安全的程序由于又鎖等臨界條件,你怎么控制步調(diào)也不會出錯。

慕沐林林
TA貢獻2016條經(jīng)驗 獲得超9個贊
你代碼中的if比較,會像樓上所說的被優(yōu)化掉,從而看不到效果。
多線程不安全,你可以搜索一下單例模式的懶漢式,他是標準的線程不安全。
public class Singleton {
private static Singleton instance = null;
private static int count =0;
private Singleton(){
System.out.println(" call constructor "+ count+" times");
count++;
}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
按照代碼的設想,singleton構(gòu)造方法應該只會被執(zhí)行一次,但如果你使用多線程的時候,你會發(fā)現(xiàn)被執(zhí)行了多次。
解決方法就是加鎖,或者使用餓漢式
添加回答
舉報
0/150
提交
取消