如何在Java中运行类的不同实例的线程之间同步静态变量?

如何在Java中运行类的不同实例的线程之间同步静态变量?,java,multithreading,synchronization,class,object,Java,Multithreading,Synchronization,Class,Object,我知道在方法将同步带到该对象之前使用synchronize关键字。也就是说,运行相同对象实例的2个线程将被同步 但是,由于同步是在对象级别进行的,因此运行对象不同实例的两个线程将不会同步。如果方法调用的Java类中有一个静态变量,我们希望它在类的实例之间同步。这两个实例在两个不同的线程中运行 我们可以通过以下方式实现同步吗 public class Test { private static int count = 0; private static final Obje

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

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

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

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
的实例之间同步,这是真的吗?

是的

如果您创建两个类的实例

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

那么t1.fo和t2.fo都在同一个静态对象上同步,因此彼此阻止。

如果只是简单地共享一个计数器,请考虑使用JavaUTI.CONCURSTON.AcEngult:

中的一个或另一个合适的类。
public class Test {

    private final static AtomicInteger count = new AtomicInteger(0); 

    public void foo() {  
        count.incrementAndGet();
    }  
}

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

  • 使用同步静态方法。这将在类对象上同步

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

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

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

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

    您可以在类上同步代码。这将是最简单的

       public class Test  
        {  
           private static int count = 0;  
           private static final Object lock= new Object();    
           public synchronized void foo() 
          {  
              synchronized(Test.class)
             {  
                 count++;  
             }  
          }  
        }
    
    希望这个答案对您有用。

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

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

    所有这些答案都是无用的,除非锁对象被声明为FINAL!另请看java.util.concurrent.AtomicInteger1。第一个甚至不需要锁对象,这不是最好的吗。将count声明为volatile也会起作用,因为volatile确保变量是同步的。最好的原因是#3的任何随机代码位都可能在
    Test.class
    上同步,并可能会破坏您的一天。另外,类初始化是在锁定类的情况下运行的,因此,如果您有疯狂的类初始化器,您可能会感到头疼<代码>易失性对计数+没有帮助,因为它是一个读/修改/写序列。正如在另一个回答中所指出的,
    java.util.concurrent.AtomicInteger
    可能是这里的正确选择。如果要读取其他线程设置的正确值,请不要忘记同步计数读取操作。声明它为volatile(除了同步写入之外)也会有帮助。@Ferrybig否,您正在锁定
    Test.class
    将是同步非静态方法的锁。此方法将起作用,但正如@Fadden在其他地方提到的,请注意,任何其他线程也可能在
    Test.class
    上同步并影响行为。这就是为什么在
    lock
    上同步可能是首选。您所说的是正确的。这就是为什么我清楚地提到上述方法是最简单的方法。一种方法会阻止另一种方法,如果小心的话,不会立即阻止另一种方法。它在Java1.5中可用,而不是在1.6中。