【问题标题】:Java Concurrency synchronization issueJava并发同步问题
【发布时间】:2017-12-17 15:11:04
【问题描述】:

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

/**
 * 
 */
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()+" ");
    }

}

【问题讨论】:

  • //read->modify->write operation 只有 readwrite 被同步(独立)。应该是单个原子操作。
  • 你能否解释一下为什么 get 和 set 操作没有获取相同的锁,因为如果它们获取相同的锁,将实现复合原子性。
  • 他们正在获取相同的锁。 “因为如果他们获得相同的锁复合原子性将实现”不,它不会,仍然有一个时间片,您可以修改根本不同步的值,其他线程可以干预。
  • 是的,明白了。谢谢。

标签: java multithreading synchronized


【解决方案1】:

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

让我们检查以下行:

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 SharedClass {
    private static int sharedData;

    public synchronized int getSharedData() {
        return sharedData;
    }

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

【讨论】:

  • 哦,我错过了一个,所以其他解决方案是使用 AtomicInteger 来防止这里的竞争条件。此外,您正在使用也可以工作的同步方法进行计算。类 SharedClass { 私有 AtomicInteger sharedData=new AtomicInteger(0);公共同步 int getSharedData() { return sharedData.getAndIncrement(); } } public void run() { System.out.print(s1.getSharedData()+" "); } }
猜你喜欢
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-10
  • 2011-09-21
  • 1970-01-01
相关资源
最近更新 更多