Как синхронизировать статическую переменную между потоками, выполняющими разные экземпляры класса в Java?
Я знаю, что с помощью 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
?
4 ответа
Есть несколько способов синхронизировать доступ к статической переменной.
Используйте синхронизированный статический метод. Это синхронизируется с объектом класса.
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 является лучшим во многих случаях, потому что объект блокировки не предоставляется за пределами вашего класса.
Если вы просто делитесь счетчиком, подумайте об использовании AtomicInteger или другого подходящего класса из пакета java.util.concurrent.atomic:
public class Test {
private final static AtomicInteger count = new AtomicInteger(0);
public void foo() {
count.incrementAndGet();
}
}
Да, это правда.
Если вы создаете два экземпляра вашего класса
Test t1 = new Test();
Test t2 = new Test();
Затем t1.foo и t2.foo синхронизируются на одном и том же статическом объекте и, следовательно, блокируют друг друга.
Мы также можем использовать 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();
}
}
Вы можете синхронизировать свой код над классом. Это было бы проще всего.
public class Test
{
private static int count = 0;
private static final Object lock= new Object();
public synchronized void foo()
{
synchronized(Test.class)
{
count++;
}
}
}
Надеюсь, вы найдете этот ответ полезным.
Если это только одно целое число, вы также можете использовать
Interlocked.Increment(count)
(пространство имен - System.Threading).