Java并发同步问题

Java Concurrency synchronization issue

任何人都可以解释为什么下面的代码会导致竞争条件,因为我使方法同步但它的对象级锁定,我正在深入研究 java 并发。 请解释,因为如果我使用class级别肯定可以,我怀疑每个线程占用的锁都不一样。

/**
 * 
 */
package lession2.shared.object;

/**
 * @author so_what
 *
 */

class SharedClass {
    private static int sharedData;

    public synchronized   int getSharedData() {
        return sharedData;
    }

    public synchronized   void setSharedData(int sharedData) {

        SharedClass.sharedData = sharedData;
    }

}

//output of the program should be the distinct numbers
public class StaleDataExample extends Thread {
    static  SharedClass s1=new SharedClass();
    static  int counter=0;
    public static  void main(String args[]) throws InterruptedException {

        StaleDataExample t1=new StaleDataExample();
        StaleDataExample t2=new StaleDataExample();
        StaleDataExample t3=new StaleDataExample();
        StaleDataExample t4=new StaleDataExample();
        StaleDataExample t5=new StaleDataExample();
        StaleDataExample t6=new StaleDataExample();
        t1.start();
        t2.start();
        t3.start();
        t4.start();

        t5.start();
        t6.start();
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        t5.join();
        t6.join();
        System.out.println();

    }
    public void run()
    {

        s1.setSharedData(s1.getSharedData()+1); //read->modify->write operation
        System.out.print(s1.getSharedData()+" ");
    }

}

这里的问题是您没有以原子(例如同步)方式增加共享值。

让我们检查以下行:

s1.setSharedData(s1.getSharedData()+1)

首先,您调用 getSharedData,即 synchronized. You then increment the value, at callsetSharedData` 来设置新值。问题是程序可以在 get 和 set 之间进行上下文切换。考虑以下示例:

  1. 线程 #1 调用 getSharedData(),并获得 0
  2. 线程 #2 调用 getSharedData(),也得到 0
  3. 线程 #1 将其值加 1,并调用 setSharedData(1).
  4. 线程 #2 也将其值加 1,并调用 setSharedData(1),而不是您期望的 setSharedData(2)

解决此类问题的一种方法是不允许 class' 用户直接设置值,而是为他们提供一种自动增加值的方法:

class SharedClass {
    private static int sharedData;

    public synchronized int getSharedData() {
        return sharedData;
    }

    public synchronized void incrementSharedData(int amount) {
        sharedData += amount;
    }
}