更新/写入静态变量的最佳实践?

Cha*_*les 5 java static findbugs

我有一个显示部门文档的项目.我将所有文档(从数据库中获取)存储在静态arrayList中.每隔X小时,我就根据数据库中的新doc(如果有的话)重建了arrayList.还有一个静态变量来控制重建该数组,在执行重建任务的方法中设置和取消设置.每个访问服务器的Web浏览器都将创建此类的实例,但doc arrayList和该控件变量在所有类实例之间共享.

Find-Bugs工具抱怨"从实例方法someClassMethod写入静态字段someArrayName和someVariableName".似乎这不是好事(让类实例方法写入静态字段).有没有人有好的建议如何解决这个问题?谢谢.

Jas*_*n S 7

根据FindBugs错误描述:

ST:从实例方法写入静态字段(ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD)

此实例方法写入静态字段.如果操作多个实例并且通常是不好的做法,这很难得到纠正.

除了并发问题之外,它意味着JVM中的所有实例都在访问相同的数据,并且不允许两个单独的实例组.如果你有一个单独的"manager"对象并将它作为构造函数参数或至少作为setManager()方法参数传递给每个实例,那会更好.

至于并发问题:如果你必须使用静态字段,你的静态字段应该是最终的; 显式同步很难.(如果你正在初始化非最终静态字段,还有一些棘手的方面,除了我对Java的了解,但我认为我已经在Java Puzzlers书中看到过它们.)至少有三种方法可以解决这个问题(警告,未经测试的代码如下,在使用前先检查):

  1. 使用线程安全的集合,例如Collections.synchronizedList包裹在未以任何其他方式访问的列表中.

    static final List<Item> items = createThreadSafeCollection();
    
    
    static List<Item> createThreadSafeCollection()
    {
       return Collections.synchronizedList(new ArrayList());
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后当你从一个实例替换这个集合时:

    List<Item> newItems = getNewListFromSomewhere();
    items.clear();
    items.add(newItems);
    
    Run Code Online (Sandbox Code Playgroud)

    这个问题是,如果两个实例同时执行此序列,您可以得到:

    Instance1:items.clear(); Instance2:items.clear(); Instance1:items.addAll(newItems); Instance2:items.addAll(newItems);

    并获得一个不符合所需类不变量的列表,即在静态列表中有两组newItems.因此,如果要将整个列表清除为一步,并将第二步添加为项,则此方法不起作用.(但是,如果您的实例只需要添加一个项目,则items.add(newItem)可以安全地从每个实例中使用.)

  2. 同步对集合的访问.

    你需要一个明确的同步机制.同步方法不起作用,因为它们在"this"上同步,这在实例之间不常见.你可以使用:

    static final private Object lock = new Object();
    static volatile private List<Item> list;
    // technically "list" doesn't need to be final if you
    // make sure you synchronize properly around unit operations.
    
    
    static void setList(List<Item> newList)
    {
      synchronized(lock)
      {
          list = newList;
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用AtomicReference

    static final private AtomicReference<List<Item>> list;
    
    
    static void setList(List<Item> newList)
    {
      list.set(newList);
    }
    
    Run Code Online (Sandbox Code Playgroud)


Meh*_*dad 0

使用单例设计模式是一种方法。您只能拥有一个保存所需值的对象实例,并通过全局属性访问该实例。优点是,如果您以后想要拥有更多实例,则对预先存在的代码的修改较少(因为您没有将静态字段更改为实例字段)。