我有一个与java线程相关的问题。
举一个非常简单的例子,假设我有2个线程。
线程正在运行的StockReader类实例
线程B运行StockAvgDataCollector类实例
在线程B中,StockAvgDataCollector连续收集一些市场数据,做一些重度平均/操作并更新成员变量spAvgData
在线程A中,StockReader可以使用getspAvgData()方法访问StockAvgDataCollector实例及其成员spAvgData。
因此,线程A仅执行READ操作,线程B执行READ / WRITE操作。
问题
现在,在这种情况下,我是否需要同步或原子功能或锁定或任何与并发相关的内容?如果线程A读取旧值,则无关紧要。
由于线程A仅进行READ而不更新任何内容,并且只有线程B执行任何WRITE操作,是否会出现任何死锁情况?
我在以下链接中粘贴了以下段落。从那一段开始,似乎我确实需要担心某种锁定/同步。
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 :(得分: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变量的可见性,可以将变量声明为volatile
或AtomicReference。此外,您需要保护更新的操作是 atomic ,以防涉及更多不变量或更新操作是复合操作,使用同步和锁定。如果只有线程B正在更新该变量,那么您不需要同步,并且可见性应足以让线程A读取变量的最新值。
答案 2 :(得分:2)
ReentrantReadWriteLock
并且在持有锁定时没有超时暂停或休眠,那么就不会出现死锁。如果您确实执行了不安全的线程操作,或者尝试推出自己的同步解决方案,那么您将需要担心它。如果您使用阻止队列,那么您还需要在StockReader
中持续运行的摄取循环。 ReadWriteLock
在单核处理器上仍然有用 - 无论线程是在物理上同时运行还是仅由上下文切换交错,问题都是相同的。
如果您不使用至少某种形式的同步(例如volatile
),那么您的读者可能永远不会看到任何变化。