【问题标题】:Static method behavior in multithreaded JAVA多线程 JAVA 中的静态方法行为
【发布时间】:2016-08-19 07:45:53
【问题描述】:

我在多线程环境中更新一个值

Class TestClass{

    public static TestObject updateTestObject (TestObject testObject )
    {
        testObject.setLatestSequence (testObject.getLatestSequence () + 1);

        return testObject ;
    }

}

该值用于另一个类似的类中。该函数是同步的,因此一次只能有一个线程进入。

Class parentClass 
{

 void synchronized updateDBSequence()
 {
      // Read old value from DB     
      TestObject testObject = readFromDAO.readTestClass(naturalKey);

     // Access in static manner, Issue ? If two threads go in, the object       
     //the return will have duplicate sequence number in it e.g. first read             
     //1 as latest sequence second also read 1 and both updated it to 2 and save in DB.

    TestClass.updateTestObject (testObject);

    // DAO has already been injected by spring
    // Update value in DB
    testObjectDAO.update (testObject);
  }

在多线程环境中运行时,有时从 testClass.updateTestObject() 方法返回的对象有重复序列,因此重复序列保存在 DB 中。我们希望它们始终是独一无二的

为了克服这个问题,函数 updateDBSequence () 已经同步,但没有解决问题,然后意识到 TestClass.updateTestObject () 函数可能导致问题,因为它是静态的并且线程在其中将不知道其他线程用什么更新了该值。

所以为了解决这个问题,Class.function 方式的访问被更改为其中的实际代码,而不是在代码中调用具有类名的静态函数。

  void synchronized updateDBSequence()
  {
      // Read old value from DB     
      TestObject testObject = readFromDAO.readTestClass(naturalKey);

     // DO not access in static manner 
       testObject.setLatestSequence (testObject.getLatestSequence () + 1);


    // DAO has already been injected by spring
    // Update value in DB
    testObjectDAO.update (testObject);
  }

它会解决问题吗?进入静态方法的线程是否不知道其他线程更新的值是什么,即他们正在处理的对象是共享的,并且每个都有自己的副本。

【问题讨论】:

  • 使用真实的数据库序列。
  • 但是在这种情况下线程的行为呢?
  • void synchronized function updateDBSequence()?那不是 Java。
  • 无法判断。太多的未知数。 DAO 做什么。什么是自然键?什么是 parentClass 以及它们有多少个实例。事务在哪里,等等。但是尝试通过线程同步来解决事务问题并不是正确的方法。如果您需要全局递增序列,请使用数据库序列,这就是它的用途。但是阅读你所有的问题和伪代码,我很难理解你想要实现的目标。
  • 总是使用 newInstance 调用父类

标签: java multithreading concurrency synchronization


【解决方案1】:

testObject.setLatestSequence (testObject.getLatestSequence () + 1);

不是原子的。

如果您使用多个parentClass 实例,updateDBSequence() 也不是原子的。

您提出的修改(使用实例)不会改变任何事情。 最好的办法是使用事务而不是重新发明轮子。

快速解决方法是在TestClass 上同步。

 void updateDBSequence()
 {
     synchronized (TestClass.class) {
        // Read old value from DB     
        TestObject testObject = readFromDAO.readTestClass(naturalKey);

        TestClass.updateTestObject (testObject);

        testObjectDAO.update (testObject);

     }
}

这将解决updateDBSequence() 的并发调用之间的问题。如果在其他方法中使用TestClassreadFromDAO,则会出现数据竞争情况。

【讨论】:

  • 如果TestClass.updateTestObject (testObject); 在没有同步的情况下在其他地方被另外调用......只是一个想法。
  • 那么我们不需要同步updateDBSequence,我们可以从方法签名中删除同步?
  • 还有很多其他方法使用TestClass和readFromDAO。这意味着该解决方案将不起作用?
猜你喜欢
  • 2013-03-19
  • 1970-01-01
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
  • 2014-01-09
  • 2011-05-14
  • 1970-01-01
  • 2023-04-09
相关资源
最近更新 更多