Подтвердить что ты не робот

Как синхронизировать или блокировать переменные в Java?

Позвольте мне использовать этот небольшой и простой пример:

class Sample {
    private String msg = null;

    public void newmsg(String x){
        msg = x;
    }

    public String getmsg(){
        String temp = msg;
        msg = null;
        return temp;
    }
}

Предположим, что функция newmsg() вызывается другими потоками, к которым у меня нет доступа.

Я хочу использовать метод synchonize, чтобы гарантировать, что строка msg используется только одной функцией за время. Другими словами, функция newmsg() не может работать одновременно с getmsg().

4b9b3361

Ответ 1

Это довольно легко:

class Sample {
    private String message = null;
    private final Object lock = new Object();

    public void newMessage(String x) {
        synchronized (lock) {
            message = x;
        }
    }

    public String getMessage() {
        synchronized (lock) {
            String temp = message;
            message = null;
            return temp;
        }
    }
}

Обратите внимание, что я не выполнял синхронизацию или синхронизацию самих методов на this. Я твердо верю, что это хорошая идея, чтобы получить только блокировки объектов, к которым имеет доступ только ваш код, если вы не намеренно раскрываете блокировку. Это намного облегчает уверенность в себе, что ничто другое не собирается приобретать блокировки в другом порядке для вашего кода и т.д.

Ответ 2

Для этой функциональности вам лучше не использовать блокировку вообще. Попробуйте AtomicReference.

public class Sample {
    private final AtomicReference<String> msg = new AtomicReference<String>();

    public void setMsg(String x) {
        msg.set(x);
    }

    public String getMsg() {
        return msg.getAndSet(null);
    }
}

Никаких блокировок не требуется, а код проще ИМХО. В любом случае он использует стандартную конструкцию, которая делает то, что вы хотите.

Ответ 3

Начиная с Java 1.5 это всегда хорошая идея, чтобы рассмотреть пакет java.util.concurrent. Это современный механизм блокировки в Java прямо сейчас. Механизм синхронизации более тяжелый, чем классы java.util.concurrent.

Пример будет выглядеть примерно так:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Sample {

    private final Lock lock = new ReentrantLock();

    private String message = null;

    public void newmsg(String msg) {
        lock.lock();
        try {
            message = msg;
        } finally {
            lock.unlock();
        }
    }

    public String getmsg() {
        lock.lock();
        try {
            String temp = message;
            message = null;
            return temp;
        } finally {
            lock.unlock();
        }
    }
}

Ответ 4

В этом простом примере вы можете просто поместить synchronized в качестве модификатора после public в обеих сигнатурах методов.

Более сложные сценарии требуют других вещей.

Ответ 5

Используйте ключевое слово synchronized.

class sample {
    private String msg=null;

    public synchronized void newmsg(String x){
        msg=x;
    }

    public synchronized string getmsg(){
        String temp=msg;
        msg=null;
        return msg;
    }
}

Использование ключевого слова synchronized для методов потребует потоков для получения блокировки в экземпляре sample. Таким образом, если какой-либо один поток находится в newmsg(), ни один другой поток не сможет получить блокировку экземпляра sample, даже если он пытался вызвать getmsg().

С другой стороны, использование методов synchronized может стать узким местом, если ваши методы выполняют длительные операции - все потоки, даже если они хотят вызывать другие методы в этом объекте, которые могут чередоваться, все равно придется ждать.

IMO, в вашем простом примере, нормально использовать синхронизированные методы, поскольку у вас на самом деле есть два метода, которые не должны чередоваться. Тем не менее, при различных обстоятельствах может возникнуть больше смысла синхронизировать объект блокировки, как показано в ответе Joh Skeet.

Ответ 6

Если в другом случае вы синхронизируете коллекцию, а не строку, возможно, вы выполняете итерацию по коллекции и беспокоитесь о ее мутации, Java 5 предлагает: