java程序为什么没有完成for循环?

时间:2018-12-12 13:47:12

标签: java

我不明白为什么每次运行此代码都会得到不同的答案? 正确的答案应该是一个98098和两个98099。任何人都有任何想法为什么不能这样工作?例如,一次答案返回“一个49047两个90047”,然后又一次返回“一个40072两个40072”。我现在很困惑,也没有任何合理的解释

public class TestThreads {
    public static void main(String[] args){

        ThreadOne t1 = new ThreadOne();
        ThreadTwo t2 = new ThreadTwo();

        Thread one = new Thread(t1);
        Thread two = new Thread(t2);

        one.start();
        two.start();

    }
}

class ThreadOne implements Runnable {
    Accum a = Accum.getAccum();
    public void run(){
        for(int x = 0; x < 98; x++){
            a.updateCounter(1000);
            try{
                Thread.sleep(50);
            }catch(InterruptedException ex){

            }
        }
        System.out.println("one " + a.getCount());
    }

}

class ThreadTwo implements Runnable {
    Accum a = Accum.getAccum();
    public void run(){
        for(int x = 0; x < 99; x++){
            a.updateCounter(1);
            try{
                Thread.sleep(50);
            }catch(InterruptedException ex){

            }
        }
        System.out.println("two " + a.getCount());
    }

}

class Accum {

    private static Accum a = new Accum();
    public static Accum getAccum(){
        return a;
    }

    private int counter = 0;

    public int getCount(){
        return counter;
    }

    public void updateCounter(int add){
        counter += add;
    }


    private Accum(){ }

}

3 个答案:

答案 0 :(得分:1)

由于有两个线程在没有线程安全的情况下更新同一数据,因此一个线程很容易覆盖另一个线程设置的值。

每个线程都使用其自己的线程缓存值。例如

线程1加1一百次。它的值为100

线程2加1000一百次。它的值为100000

此时,选择一个值。说这是线程1的值。

线程1加1一百次。它的值为200

线程2加1000一百次。它的值为100100

这次,选择线程2的值。

最后,平均保留了一半的更新,因为选择的值有些随机。

答案 1 :(得分:1)

您可以通过将Accum中的方法声明为已同步来获得98099。

这将确保每次只有一个线程可以访问其信息。

正如其他答案所指出的那样,您将获得意想不到的结果,因为没有什么可以阻止每个线程覆盖另一个线程所做的事情。

尝试一下:

class Accum {

    private static Accum a = new Accum();
    public static synchronized Accum getAccum(){
        return a;               
    }

    private int counter = 0;

    public synchronized int getCount(){
        return counter;
    }

    public synchronized void updateCounter(int add){
        counter += add;
    }


    private Accum(){ }

}

答案 2 :(得分:0)

您的问题是这个

 private static Accum a = new Accum();
 public static Accum getAccum(){
    return a;
}

由于其为STATIC,因此所有线程仅共享一个实例。因此,当您在一个线程中设置它时,所有线程都会获得相同的新值。如果您删除了静态通知程序并为每个线程实例化一个Accum类的新对象,那么它将起作用。