【问题标题】:Java static variable updatesJava 静态变量更新
【发布时间】:2012-11-22 11:07:08
【问题描述】:

您可以在下面看到一个 Java 类中的静态变量 counter

问题是这个变量什么时候会重置?例如,当我重新启动程序时,计算机。它可以重置的其他可能情况是什么?

另一个问题是:这个变量增加的次数少于函数 do() 执行次数的原因是什么?例如,是否可以启动 java Whatever 类的多个进程?或者它可能是具有多个线程/服务器等的东西?

class Whatever {

    static int counter = 0;

    function do() {
        counter++;
        //...
    }

}

附加问题:如果多个线程执行函数do(),计数器变量将如何表现?会小于函数do()的执行次数吗?

【问题讨论】:

  • static 变量仅在程序执行开始时初始化一次。
  • 您的counter 是包私有的,因此同一个包中的任何类都可以为其分配任意值。
  • 顺便说一句,do 是保留关键字,不能用作方法名。

标签: java static static-members


【解决方案1】:

当您重新启动应用程序时,将重新初始化静态变量。

【讨论】:

    【解决方案2】:

    根据JLS

    如果一个字段被声明为静态,那么无论最终创建多少个类的实例(可能为零),都只存在该字段的一个化身。静态字段,有时称为类变量,在类初始化时体现

    所以这回答了你的第一个问题。即恰好在加载类时:)

    根据第二个问题,不。如果变量被声明为私有的。那么由于封装,唯一的访问是通过方法。

    静态变量一直持续到 JVM 关闭。

    【讨论】:

      【解决方案3】:

      counter 不是私有变量。所以这个值有可能被其他类改变了。

      只要您的程序(或特别是容器/jvm)被重述,该变量就会被重置。

      【讨论】:

        【解决方案4】:

        1) 加载类时设置(重置)变量。除了关闭 JVM 之外,一些服务器会在不同的应用程序(例如 Tomcat 网络应用程序)中加载该类,其中一些允许重新启动它们。

        2) 线程并发修改。但它应该很少见,除非你经常使用它。使用synchronized 作为函数/块。

        【讨论】:

        • 如果多个线程访问它,计数器变量将如何处理?会小于函数do()的执行次数吗?
        • 是的。想想counter 是 2; thread1 进行运算,计算 ++ 检索 2 并添加 3,但在将 2 替换为 3 之前,thread2 开始运算,检索到 counter 仍为 2,并将结果计算为 3。最后两个线程将counter的值设置为3,而其中一个应该设置为4。这称为并发或运行条件。
        【解决方案5】:

        问题是这个变量什么时候重置?

        可以使用自定义reset() 方法重置静态变量。如果您说重新启动程序,理论上该变量将被初始化为它的值而不是重新初始化,因为它不一样(您重新启动程序)。

        【讨论】:

          【解决方案6】:
          class Foo { // in same package
          public static void main(String[] args) {
              Whatever w = new Whatever();
              for (int i = 0; i < 1000; i++) {
                  w.do();
              }
              Whatever.counter = -1;
          }
          

          这里 do() 被调用了 1000 次,但 counter 最后将具有价值。

          我在您的示例中像您一样使用了 do(),但请注意,这不是有效的方法名称,因为它是 do while 循环的关键字。

          【讨论】:

            【解决方案7】:

            静态变量意味着在程序执行期间该字段只有一个化身。它在类初始化时加载。

            对于第二个问题,您的变量不是线程安全的,因为多个线程可以同时访问它。 即使您的计数器不稳定,您仍然会面临并发问题。 根据您的示例和要求,您有三个选择:

            如果您的唯一要求是操纵变量并且其余代码不依赖于该变量,您可以使用同步(用大炮杀死苍蝇)或AtomicInteger(性能更好的选择):

            static synchronize int counter = 0;
            // or
            static AtomicInteger counter = new AtomicInteger();
            

            如果您的其余代码依赖于您的计数器,则必须使用锁定对象或同步您的方法:

            class Whatever {
            
                static int counter = 0;
            
                synchronize function do() {
                    counter++;
                    if(counter < 10){
                        //  do something
                    }
                }
            }
            
            //  or
            
            class Whatever {
            
                static int counter = 0;
                static final Object _lock = new Object();
            
                function do() {
                    synchronized (_lock) {
                        counter++;
                        if(counter < 10){
                            //  do something
                        }
                    }
                }
            }
            

            这是我现在脑海中的选项,但可能还有更多。

            【讨论】:

              猜你喜欢
              • 2015-08-14
              • 1970-01-01
              • 1970-01-01
              • 2021-10-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多