1

我有一个对象 obj,它被许多线程频繁读取,但仅由一个线程定期更新。更新发生在很长一段时间后(比如 10 分钟)。

数据不那么跨国。意味着如果读取线程在一段时间内获得陈旧数据(旧),那么它完全可以。

现在我想到了使用以下方法进行同步:

final Object lock = new Object();
private MyObject obj = new MyObject(); //this is the data

public String getDataFieldName(){
 synchronized(lock){
   return this.obj.name;
 }
}


/*the following code is wrong right?As its just synchronizes the code for getting reference.But after getting reference read thread R1 may try to get data while write Thread is modifying data.Will that give exception?How to solve this? */
public String getData(){
 synchronized(lock){
   return this.obj;
 }
}

//only one thread can update.But how multipe threads can read at once?
public updateData(args ) {
  synchronized(lock){
    //do update
 }

}

我的问题如下:

  1. 我不希望只有一个线程来读取数据。读取应该是并行的。

  2. 我如何同步读取和写入?如果写入线程正在更新并且读取线程正在读取我不会得到一些异常。如果读取得到一些旧数据也没关系 3)如果读取线程正在读取而写入线程正在更新,我会得到异常?会不会有什么问题?

4

2 回答 2

1

在这种情况下,您不需要任何同步。您所要做的就是:

  • 确保MyObject不可变的,这意味着您永远不会更改对象中的任何值相反,MyData每次更改时都构造一个新对象。这可以防止任何人看到半变化的对象。
  • 将obj 声明为volatile,以确保所有线程每次都能看到更新的值。

如果您遵循这些步骤,您将永远不会因为并发读取和写入而出现异常。

于 2012-07-04T05:27:48.620 回答
0
  1. 使用 volatile 关键字,与同步不同,它不会获取锁,并且会提供多重访问,反映一个线程对另一个线程的更新。

  2. 但是最好有某种同步,因为 volatile 不能确保防止数据上的竞争条件。因此,如果您不想使用同步,那么最好使用不可变对象

例如:

import java.util.Date;

/**
* Planet is an immutable class, since there is no way to change
* its state after construction.
*/
public final class Planet {


 //Final primitive data is always immutable.

  private final double fMass;

  private final String fName;

  private final Date fDateOfDiscovery;

  public Planet (double aMass, String aName, Date aDateOfDiscovery) {
     fMass = aMass;
     fName = aName;
     //make a private copy of aDateOfDiscovery
     //this is the only way to keep the fDateOfDiscovery
     //field private, and shields this class from any changes that 
     //the caller may make to the original aDateOfDiscovery object
     fDateOfDiscovery = new Date(aDateOfDiscovery.getTime());
  }


  public double getMass() {
    return fMass;
  }


  public String getName() {
    return fName;
  }




  public Date getDateOfDiscovery() {
    return new Date(fDateOfDiscovery.getTime());
  }


}
于 2012-07-04T06:15:03.807 回答