Как синхронизировать или заблокировать переменные в Java? - PullRequest
64 голосов
/ 03 мая 2011

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

class Sample {
    private String msg = null;

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

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

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

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

Ответы [ 6 ]

150 голосов
/ 03 мая 2011

Это довольно просто:

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.Я твердо верю, что хорошей идеей является получение блокировок только для объектов, к которым имеет доступ только ваш код, если только вы не намеренно выставляете блокировку.Намного легче убедить себя в том, что ничто другое не получит блокировки в другом порядке по отношению к вашему коду и т. Д.

48 голосов
/ 03 мая 2011

Для этой функции лучше не использовать блокировку вообще. Попробуйте 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);
    }
}

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

7 голосов
/ 03 мая 2011

В 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();
        }
    }
}
2 голосов
/ 03 мая 2011

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

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

1 голос
/ 03 мая 2011

Используйте ключевое слово 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, в вашем простом примере можно использовать синхронизированные методы, поскольку у вас есть два метода, которые не должны чередоваться.Однако при других обстоятельствах может иметь смысл иметь синхронизируемый объект блокировки, как показано в ответе Джо Скита.

0 голосов
/ 17 января 2014

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...