Java多线程竞争条件场景

Java多线程竞争条件场景

问题描述:

我正在经历多线程中的竞争条件,并且想到创建导致竞争条件的情况,我为此写了一个简单的程序,但每次都得到正确的结果。需要知道这是否是比赛状况的正确情况。如下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

由于所有线程都添加到字段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,是的,这是真的。我编辑了答案。 –

您的代码确实模拟竞态条件,因为添加涉及读取和写入。但是为了在这里真实地展示竞争性,你需要一些非常不幸的调度,因为所有的线程都是加法。您可能想要尝试在不同的机器上运行此操作,或者让一些线程执行其他操作,例如devision或subtraction。

另一种方法是通过在addTo()中添加来确保竞争条件。