2017-11-25 100 views
0

我正在經歷多線程中的競爭條件,並且想到創建導致競爭條件的情況,我爲此寫了一個簡單的程序,但每次都得到正確的結果。需要知道這是否是比賽狀況的正確情況。如下Java多線程競爭條件場景

代碼:

package com.threads; 

/** 
* demonstrate race conditions 
*/ 

public class Step4 { 

public int getA() { 
    return a; 
} 

public void addToA(int number) { 

    for(int i=0;i<number;i++) 
     this.a = this.a + 1; 
} 

int a = 2; 
static Step4 s4 = new Step4(); 

public static void main(String[] args) throws InterruptedException { 
    Thread thread1 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(5); 
     } 
    }); 

    Thread thread2 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(3); 
     } 
    }); 

    Thread thread3 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(6); 
     } 
    }); 

    Thread thread4 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(4); 
     } 
    }); 


    thread1.start();  
    thread2.start();  
    thread3.start(); 
    thread4.start(); 

    thread1.join(); 
    thread2.join(); 
    thread3.join(); 
    thread4.join(); 

    System.out.println(s4.getA()); 

} 

} 

//輸出20總是在我的機器中,Win7 32位。

+3

很可能每個線程在這裏做的工作很少,以至於它們根本不重疊。 –

+0

您正在等待所有4個線程來完成(join()方法),所以當然,一旦** println **被調用,內容始終爲20.所以不,它不會模擬競態條件。 –

+2

使涉及的數字更大。競爭條件是不可預測的,因此每個線程花費更多時間會增加發生的可能性。 – Kiskae

回答

0

由於所有線程都添加到字段a,所以該命令確實會影響最終結果,因此您的程序由於競爭狀態而遭受的可能性非常低。 只有當兩個線程讀取相同的值a,然後第一個分配一個新的值,然後第二個分配一個新的值,你可以「失去」一個增量。

下面是修改後的版本更頻繁地從競爭條件患有:

public class Step4 { 

    public int getA() { 
    return a; 
    } 

    public void addToA(int number) { 
    try { 
     Thread.sleep(100); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 

    for(int i=0;i<number;i++) 
     this.a = this.a + 1; 
    } 

    public void multiplyA(int number) { 
    try { 
     Thread.sleep(100); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 

    this.a = this.a * number; 
    } 

    int a = 2; 
    static Step4 s4; 

    public static void main(String[] args) throws InterruptedException { 

    for (int i = 0; i < 10; i++) { 
     s4 = new Step4(); 
     doRun(); 
     System.out.println("*******"); 
    } 
    } 

    private static void doRun() throws InterruptedException { 
    Thread thread1 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(5); 
     } 
    }); 

    Thread thread2 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.multiplyA(3); 
     } 
    }); 

    Thread thread3 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(6); 
     } 
    }); 

    Thread thread4 = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      s4.addToA(4); 
     } 
    }); 


    thread1.start(); 
    thread2.start(); 
    thread3.start(); 
    thread4.start(); 

    thread1.join(); 
    thread2.join(); 
    thread3.join(); 
    thread4.join(); 

    System.out.println(s4.getA()); 

    } 

} 

我添加了一個100毫秒的睡眠這兩個動作,以增加獲得不同的結果的機會。 大部分時間結果將是31,但在其他時間可能是17,21或51。

+1

它確實遭受競爭狀態的影響。兩個線程可以並行讀取a的當前值,然後增加它,這樣就會失去一個增量。 –

+0

@JBNizet,是的,這是真的。我編輯了答案。 –

0

您的代碼確實模擬競態條件,因爲添加涉及讀取和寫入。但是爲了在這裏真實地展示競爭性,你需要一些非常不幸的調度,因爲所有的線程都是加法。您可能想要嘗試在不同的機器上運行此操作,或者讓一些線程執行其他操作,例如devision或subtraction。

另一種方法是通過在addTo()中添加來確保競爭條件。