【问题标题】:How to synchronize a static variable among threads running different instances of a class in Java?java - 如何在Java中运行类的不同实例的线程之间同步静态变量?
【发布时间】:2011-01-08 09:07:53
【问题描述】:

我知道在方法之前使用synchronize 关键字会同步到该对象。也就是说,运行同一对象实例的 2 个线程将被同步。

但是,由于同步是在对象级别进行的,因此运行对象不同实例的 2 个线程将不会同步。如果我们在方法调用的 Java 类中有一个静态变量,我们希望它在类的实例之间同步。这两个实例在 2 个不同的线程中运行。

我们可以通过以下方式实现同​​步吗?

public class Test  
{  
   private static int count = 0;  
   private static final Object lock= new Object();    
   public synchronized void foo() 
  {  
      synchronized(lock)
     {  
         count++;  
     }  
  }  
}

既然我们已经定义了一个静态对象lock,并且我们使用关键字synchronized 锁定该锁,那么静态变量count 现在是否在类Test 的实例之间同步?

【问题讨论】:

  • 所有这些答案都是无用的,除非锁定对象被声明为 FINAL!
  • 还要看java.util.concurrent.atomic.AtomicInteger

标签: java multithreading synchronization class object


【解决方案1】:

我们也可以使用ReentrantLock来实现静态变量的同步。

public class Test {

    private static int count = 0;
    private static final ReentrantLock reentrantLock = new ReentrantLock(); 
    public void foo() {  
        reentrantLock.lock();
        count = count + 1;
        reentrantLock.unlock();
    }  
}

【讨论】:

    【解决方案2】:

    您可以通过类同步您的代码。那将是最简单的。

       public class Test  
        {  
           private static int count = 0;  
           private static final Object lock= new Object();    
           public synchronized void foo() 
          {  
              synchronized(Test.class)
             {  
                 count++;  
             }  
          }  
        }
    

    希望这个答案对您有用。

    【讨论】:

    • 这会起作用,但正如@Fadden 在别处提到的,请注意任何其他线程也可能在Test.class 上同步并影响行为。这就是为什么在 lock 上同步可能是首选的原因。
    • 你说的是对的。这就是为什么我明确提到上面是最简单的方法。
    【解决方案3】:

    有几种方法可以同步访问静态变量。

    1. 使用同步的静态方法。这会在类对象上同步。

      public class Test {
          private static int count = 0;
      
          public static synchronized void incrementCount() {
              count++;
          }
      } 
      
    2. 在类对象上显式同步。

      public class Test {
          private static int count = 0;
      
          public void incrementCount() {
              synchronized (Test.class) {
                  count++;
              }
          }
      } 
      
    3. 在其他静态对象上同步。

      public class Test {
          private static int count = 0;
          private static final Object countLock = new Object();
      
          public void incrementCount() {
              synchronized (countLock) {
                  count++;
              }
          }
      } 
      

    方法 3 在许多情况下是最好的,因为锁定对象不会暴露在你的类之外。

    【讨论】:

    • 1.第一个甚至不需要锁对象,不应该是最好的吗?
    • 2.将 count 声明为 volatile 也可以,因为 volatile 确保变量是同步的。
    • #3 最好的原因是任何随机代码位都可以在Test.class 上同步,并可能破坏您的一天。此外,类初始化运行时会锁定所持有的类,所以如果你有疯狂的类初始化器,你可能会让自己头疼。 volatilecount++ 没有帮助,因为它是读/修改/写序列。如另一个答案所述,java.util.concurrent.atomic.AtomicInteger 可能是这里的正确选择。
    • 如果要读取其他线程设置的正确值,请不要忘记同步计数上的读取操作。将其声明为 volatile(除了同步写入)也将对此有所帮助。
    • @Ferrybig 不,您正在锁定 Test.classthis 将是同步非静态方法的锁
    【解决方案4】:

    如果您只是共享一个计数器,请考虑使用 AtomicInteger 或 java.util.concurrent.atomic 包中的另一个合适的类:

    public class Test {
    
        private final static AtomicInteger count = new AtomicInteger(0); 
    
        public void foo() {  
            count.incrementAndGet();
        }  
    }
    

    【讨论】:

    • 它在 java 1.5 中可用,在 1.6 中不可用。
    【解决方案5】:

    是的,这是真的。

    如果你创建了你的类的两个实例

    Test t1 = new Test();
    Test t2 = new Test();
    

    然后 t1.foo 和 t2.foo 都在同一个静态对象上同步,因此相互阻塞。

    【讨论】:

    • 一个人会阻止另一个人,如果小心的话,不会立即互相阻止。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    相关资源
    最近更新 更多