即使在同步后也会出现竞争状况

时间:2016-04-30 23:40:48

标签: java multithreading

我正在尝试运行多个线程。我显然已经获得了竞争条件,并且能够按如下方式解决它:

final Data data = new Data();
for (int i = 0; i < numberOfThreads; i++) {
    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            //using this sync block to stop the race condition 
            synchronized (data){
                final int value = data.getValue();
                data.setValue(value + 1);
            }
        }
    });
    thread.start();
}

但我不想在这个块上进行同步,而是希望在Data类中处理它。所以我删除了上面的同步块,而是在Data类中同步get和set方法,如下所示,但这仍然会导致竞争条件。为什么这个问题即使我已经同步了?

public class Data {

    private int value;

    public synchronized int getValue(){
        return this.value;
    }

    public synchronized void setValue(int num){
        this.value = num;
    }
}

4 个答案:

答案 0 :(得分:4)

因为你没有。您同步了其中任何一个,因此两个线程无法同时执行这些方法,但是一个线程可以执行getValue()然后完成getValue(),在它进入setValue()之前,另一个线程轮到它了致电getValue()这是完全合法的,也是你的竞争条件。

顺便说一下。为了防止Data成为你的整个班级,AtomicInteger将是相同的,但做得恰当。你在那里。 G。有一个incrementAndGet()方法可以在一个同步块中执行读写操作,这是您案例的基本点。

答案 1 :(得分:2)

synchronized添加到各个方法类似于执行此类操作

final Data data = new Data();
for (int i = 0; i < numberOfThreads; i++) {
    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (data){
                final int value = data.getValue();
            }
            synchronized (data){
                data.setValue(value + 1);
            }
        }
    });
    thread.start();
}

线程可能非常明显地卡在get和set之间。要解决此问题,您需要向完成Data任务的value + 1类添加新的同步方法,或者在synchronized块中包含两行,就像在您的代码。

答案 2 :(得分:1)

首先,在 String res=""; Integer opt=Integer.parseInt(JOptionPane.showInputDialog("How many numbers do you need?")); for (int i=0; i<opt; i++) { String numbers=JOptionPane.showInputDialog("Add your numbers"); res += numbers; } String reversedString = new StringBuilder(res).reverse().toString(); JOptionPane.showMessageDialog(null,"Your numbers are "+ reversedString); 班级中Data应该是value

关于你提到的问题;你不能像你一样改变代码。 因为在你改变它的方式可能会发生以下情况:

  

1)volatilevalueData

     

2)0读取Thread 0(读取value

     

3)0读取Thread 1(读取value

     

4)0递增Thread 1并将新值写入value(写Data.value

     

5)1递增Thread 0并将新值写入value(写Data.value

此处的问题是,在步骤5)中编写了1,因为1Thread 0读取Thread 1而不知道value已经增加Thread 0 value

答案 3 :(得分:0)

您在方法级别添加了synchronized。所以一个线程可以调用getValue(),一个可以调用setValue()。您可以完全删除同步并将私有“值”成员的类型更改为AutomicInteger。然后在该类中使用线程安全方法。