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

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

但是,由于同步是在对象级别,运行该对象的不同实例的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的实例之间是同步的,这是真的吗?

173090 次浏览

是的,这是真的。

如果创建类的两个实例

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

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

如果只是共享一个计数器,可以考虑使用 AtomicInteger或 java.util.concurrent.atom 包中的其他合适类:

public class Test {


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


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

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

  1. 使用同步的静态方法。该方法在类对象上进行同步。

    public class Test {
    private static int count = 0;
    
    
    public static synchronized void incrementCount() {
    count++;
    }
    }
    
  2. Explicitly synchronize on the class object.

    public class Test {
    private static int count = 0;
    
    
    public void incrementCount() {
    synchronized (Test.class) {
    count++;
    }
    }
    }
    
  3. Synchronize on some other static object.

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

Method 3 is the best in many cases because the lock object is not exposed outside of your class.

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

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