更新/写入静态变量的最佳实践? [英] Best practice for updating/writing to static variable?

查看:145
本文介绍了更新/写入静态变量的最佳实践?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a project which displays department documentation. I store all the docs (get from database) in a static arrayList. Every X hour, I have that arrayList rebuilt based on the new doc (if any) from the database. There is also a static variable to control to rebuild that array or not, set and unset in a method which does the rebuild task. Each web browser hit the server will create this class's instance, but the doc arrayList and that control variable is shared among all the class instances.

查找错误工具抱怨从实例方法someClassMethod写入静态字段someArrayName和someVariableName".似乎这不是一件好事(让类实例方法写入静态字段).有谁有很好的建议如何解决这个问题?谢谢.

Find-Bugs tool complains that "Write to static field someArrayName and someVariableName from instance method someClassMethod". Seems this is not the good thing to do (let class instance method write to static field). Does anyone have good recommendation how to get around this problem ? Thanks.

推荐答案

每个 FindBugs错误描述:

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

此实例方法写入一个静态字段.如果要操纵多个实例,要想正确就很难,这通常是不好的做法.

This instance method writes to a static field. This is tricky to get correct if multiple instances are being manipulated, and generally bad practice.

除了并发问题外,这意味着JVM中的所有实例都在访问相同的数据,并且不允许两个单独的实例组.最好有一个单例管理器"对象,并将其作为构造函数参数或至少作为setManager()方法参数传递给每个实例.

Aside from the concurrency issues, it means that all of the instances in the JVM are accessing the same data, and would not allow two separate groups of instances. It would be better if you had a singleton "manager" object and passed it to each of the instances as a constructor parameter or at least as a setManager() method argument.

关于并发性问题:如果必须使用静态字段,则您的静态字段应该是最终字段;显式同步是困难的. (如果您要初始化非最终静态字段,还有一些棘手的方面,这超出了我对Java的了解,但是我想我已经在Java Puzzlers一书中看到了它们.)至少有三种处理此问题的方法(警告,未经测试的代码如下,请先检查后再使用):

As for the concurrency issues: if you must use a static field, your static field should be final; explicit synchronization is difficult. (There are also some tricky aspects if you are initializing non-final static fields, beyond my knowledge of Java but I think I've seen them in the Java Puzzlers book.) There are at least three ways of dealing with this (warning, untested code follows, check first before using):

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

  1. Use a thread-safe collection, e.g. Collections.synchronizedList wrapped around a list that is not accessed in any other way.

static final List<Item> items = createThreadSafeCollection();


static List<Item> createThreadSafeCollection()
{
   return Collections.synchronizedList(new ArrayList());
}

,然后在您替换实例中的该集合时,稍后:

and then later when you are replacing this collection, from an instance:

List<Item> newItems = getNewListFromSomewhere();
items.clear();
items.add(newItems);

问题在于,如果两个实例同时执行此序列,则可能得到:

The problem with this is that if two instances are doing this sequence at the same time, you could get:

Instance1:item.clear(); 实例2:item.clear(); 实例1:item.addAll(newItems); 实例2:item.addAll(newItems);

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

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

and get a list that doesn't meet the desired class invariant, namely that you have two groups of newItems in the static list. So this method doesn't work if you are clearing the entire list as one step, and adding items as a second step. (If your instances just need to add an item, though, items.add(newItem) would be safe to use from each instance.)

同步对集合的访问.

您将需要在此处进行同步的显式机制.同步方法不起作用,因为它们在"this"上同步,这在实例之间并不常见.您可以使用:

You'll need an explicit mechanism for synchronizing here. Synchronized methods won't work because they synchronize on "this", which is not common between the instances. You could use:

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;
  }
}

  • 使用AtomicReference

  • use AtomicReference

    static final private AtomicReference<List<Item>> list;
    
    
    static void setList(List<Item> newList)
    {
      list.set(newList);
    }
    

  • 这篇关于更新/写入静态变量的最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆