2011-02-08 29 views
5

我有一个Java线程相关的问题。Java线程同步,最佳并发实用程序,读操作

举一个非常简单的例子,可以说我有2个线程。

线程A运行StockReader Class实例

线程B运行StockAvgDataCollector Class实例

在线程B,StockAvgDataCollector收集一些市场数据连续地,做了一些重均值/处理和更新的成员变量spAvgData

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

因此,线程A只执行读操作,线程B执行读/写操作。

问题

  1. 现在,我需要在这种情况下同步或原子功能或锁定或并发相关的东西?线程A读取较旧的值并不重要。

  2. 因为线程A只进行读取操作而不更新任何内容,只有线程B执行任何写入操作,是否会出现死锁情况?

我从以下链接粘贴了一段。从该段看来,我确实需要担心某种锁定/同步。

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()方法将被暴露。

感谢 阿米特

+0

对不起,我不知道。刚刚接受了我之前的所有问题。感谢您指出。 – FatherFigure 2011-02-08 23:53:47

回答

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(); 
    } 
    } 
} 
+0

谢谢你的回答,我认为他们都很好,值得同等接受。但是,stackoverflow只允许一个答案被接受。 – FatherFigure 2011-02-11 00:21:10

2
  1. 如果你不介意,线程A可以阅读完整的废话(包括部分更新的数据)则没有,你不需要任何同步。不过,我怀疑你应该介意。
  2. 如果您只使用单个互斥锁或ReentrantReadWriteLock,并且在锁定时不会暂停或未超时休眠,则不会发生死锁。如果您确实执行不安全的线程操作,或尝试推出自己的同步解决方案,那么您将需要担心它。

如果您使用阻塞队列,那么您还需要一个持续运行的摄入循环StockReaderReadWriteLock在单核处理器上仍然有用 - 无论线程是同时物理运行还是仅通过上下文切换进行交织,问题都是相同的。

如果您至少不使用某种形式的同步(例如volatile),那么您的读者可能根本没有看到任何更改。

+0

谢谢。良好的信息。 – FatherFigure 2011-02-11 00:22:14

3

是,同步是非常重要的,你需要考虑两个参数:spAvgData变量知名度原子及其更新。为了保证线程A的线程B中的spAvgData变量的可见性,变量可以被声明为volatileAtomicReference。此外,如果涉及更多不变量或更新操作是复合操作(使用同步和锁定),则还需要警惕更新的操作是原子。如果只有线程B正在更新该变量,则不需要同步,并且可见性应该足以让线程A读取变量的最新值。

+0

虽然,Java Spec保证int(和更小)和引用的更新是原子的,所以volatile或int对象引用将起作用,后者提供的对象正在被作者替换。 – 2011-02-09 03:15:53