0
public class Rule{
 private Integer ruleId;
 private String name;
 private Date startdate;
 private Date endDate;

 // getters & setters
}
public class ClassA{
  public static List<Rule> ruleList = new ArrayList<Rule>();
  public void populateRule(){
   //Retrieve all rules; Here the rules are being added or deleted by the administration.
   //So it is required to retrieve the rules every time the Job runs.
    ruleList.clear();
    ruleList.addAll(RuleService.retrieveRules());
  }
}

public class UserClassA1{
  ClassA oClassA=Factory.getInstance(ClassA.class);
  List<Rule> rules=oClassA.populateRule();
  for(Rule oRule:rules){
  // do some stuff.
  } 
}
public class UserClassA2{
 ClassA oClassA=Factory.getInstance(ClassA.class);
List<Rule> rules=oClassA.populateRule();
for(Rule oRule:rules){
  // do some stuff.
  } 
}

在这里,UserClassA1 和 UserClassA2 正在执行不同的活动,但都使用相同的静态列表,并且当它们开始时,它们会重置列表并填充新列表。

我的问题是,当 UserClassA1 在填充列表后开始工作时,UserClassA2 开始执行并清除列表,然后去填充列表。在清除列表直到填充列表之后的这段时间间隔内,UserClassA1 无法正常运行,因为列表是清除。

我想锁定 ruleList 列表,这样当任何实例填充列表时,其他实例都不会使用该列表。

请帮助..

4

5 回答 5

1

在 classA 中,将您的 ruleList 声明为 CopyOnWriteArrayList(在 java.util.concurrent 中)。每次更改列表时,我都会制作一个新副本。列表中的现有迭代器将不受任何写操作的影响。

这样,您仍将拥有一个 ruleList 实例,但它将是线程安全的。

Javadoc:http ://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

于 2012-08-17T15:34:49.497 回答
0

简单(尽管蛮力)的方法是使用Collections.synchronizedList();

public static List<Rule> ruleList = Collections.synchronizedList(new ArrayList<Rule>());
于 2012-08-06T07:30:47.450 回答
0

我假设您需要以一致的状态(完全填充)查看列表。你可以从ruleList私有化开始。并确保 2 个线程不能同时填充它,请populateRule同步。

但是除非ClassA有其他需要访问的方法,否则ruleList你的类的防御性、线程安全和更简单的版本可能是:

public class ClassA{
    public void populateRule() {
        //Retrieve all rules; Here the rules are being added or deleted by the administration.
        //So it is required to retrieve the rules every time the Job runs.
        return Collections.unmodifiableList(RuleService.retrieveRules());
    }
}
于 2012-08-06T07:00:10.730 回答
0

您应该考虑更改ClassA以向每个populateRule方法调用者分发新列表。这样,调用者可以以任何他们认为合适的方式使用返回的列表,而不必担心后续调用populateRule. 例如:

public class ClassA {
  public List<Rule> populateRule() {
    // Retrieve all rules; Here the rules are being added or deleted by 
    // the administration. So it is required to retrieve the rules every 
    // time the Job runs.
    return new ArrayList(RuleService.retrieveRules());
  }
}
于 2012-08-06T23:07:37.563 回答
0

标准答案是,将访问列表的代码包装在synchronized(ClassA.ruleList) { ... }. 然而,使用synchronized原语等很容易出错,您应该始终尝试使用更高级别的构造java.util.concurrent,例如Lock.

但是,在这种情况下,我鼓励您考虑稍微重构代码。ruleList例如,在因子方法中创建一个局部变量怎么样?

于 2012-08-06T06:55:29.447 回答