Java线程同步,最佳并发实用程序,读取操作

时间:2011-02-08 23:17:21

标签: java multithreading

我有一个与java线程相关的问题。

举一个非常简单的例子,假设我有2个线程。

线程正在运行的StockReader类实例

线程B运行StockAvgDataCollector类实例

在线程B中,StockAvgDataCollector连续收集一些市场数据,做一些重度平均/操作并更新成员变量spAvgData

在线程A中,StockReader可以使用getspAvgData()方法访问StockAvgDataCollector实例及其成员spAvgData。

因此,线程A仅执行READ操作,线程B执行READ / WRITE操作。

问题

  1. 现在,在这种情况下,我是否需要同步或原子功能或锁定或任何与并发相关的内容?如果线程A读取旧值,则无关紧要。

  2. 由于线程A仅进行READ而不更新任何内容,并且只有线程B执行任何WRITE操作,是否会出现任何死锁情况?

  3. 我在以下链接中粘贴了以下段落。从那一段开始,似乎我确实需要担心某种锁定/同步。

    http://java.sun.com/developer/technicalArticles/J2SE/concurrency/

    读者/作家锁定

    使用线程从对象读取数据时,您不一定需要阻止另一个线程同时读取数据。只要线程只是读取而不是更改数据,就没有理由不能并行读取。 J2SE 5.0 java.util.concurrent.locks包提供了实现此类锁定的类。 ReadWriteLock接口维护一对关联的锁,一个用于只读,一个用于写入。只要没有编写器,readLock()可以由多个读取器线程同时保持。 writeLock()是独占的。虽然从理论上讲,很明显使用读取器/写入器锁来增加并发性会导致性能提高而不是使用互斥锁。然而,这种性能改进只能在多处理器上完全实现,并且与被修改的数据相比,读取数据的频率以及读取和写入操作的持续时间。

    在我的示例中,哪个并发实用程序会更便宜且更合适?

    java.util.concurrent.atomic?

    java.util.concurrent.locks?

    java.util.concurrent.ConcurrentLinkedQueue? - 在这种情况下,StockAvgDataCollector将添加并且StockReader将删除。不会暴露getspAvgData()方法。

    由于 阿米特

3 个答案:

答案 0 :(得分:3)

好吧,当你有很多读者和至少一个作家时,整个ReadWriteLock的东西真的很有意义......所以你保证活泼(如果没有其他人写的话,你就不会阻止任何读者线程)。但是,您只有两个线程。

如果您不介意线程B读取spAvgData的旧(但未损坏)值,那么我会选择AtomicDouble(或AtomicReference,具体取决于spAvgData的数据类型)。

所以代码看起来像这样

public class A extends Thread {
  // spAvgData
  private final AtomicDouble spAvgData = new AtomicDouble(someDefaultValue);

  public void run() {
    while (compute) {
     // do intensive work
     // ...
      // done with work, update spAvgData
     spAvgData.set(resultOfComputation);
    }
  }

  public double getSpAvgData() {
    return spAvgData.get();
  }
}
// --------------

public class B {
  public void someMethod() {
    A a = new A();
    // after A being created, spAvgData contains a valid value (at least the default)
    a.start();
    while(read) {
      // loll around
      a.getSpAvgData();
    }
  }
}

答案 1 :(得分:3)

是的,同步很重要,您需要考虑两个参数:spAvgData变量的可见性和其更新的原子性。为了保证线程A中线程B中spAvgData变量的可见性,可以将变量声明为volatileAtomicReference。此外,您需要保护更新的操作是 atomic ,以防涉及更多不变量或更新操作是复合操作,使用同步和锁定。如果只有线程B正在更新该变量,那么您不需要同步,并且可见性应足以让线程A读取变量的最新值。

答案 2 :(得分:2)

  1. 如果您不介意线程A可以读取完全无意义(包括部分更新的数据),那么不需要,您不需要任何同步。但是,我怀疑你应该介意。
  2. 如果您只使用一个互斥锁,或ReentrantReadWriteLock并且在持有锁定时没有超时暂停或休眠,那么就不会出现死锁。如果您确实执行了不安全的线程操作,或者尝试推出自己的同步解决方案,那么您将需要担心它。
  3. 如果您使用阻止队列,那么您还需要在StockReader中持续运行的摄取循环。 ReadWriteLock在单核处理器上仍然有用 - 无论线程是在物理上同时运行还是仅由上下文切换交错,问题都是相同的。

    如果您不使用至少某种形式的同步(例如volatile),那么您的读者可能永远不会看到任何变化。