Синхронизация, когда использовать или не использовать?

Я начал изучать совместимость и потоки в Java. Я знаю основы синхронизированного (то есть, что он делает). Концептуально я понимаю, что он обеспечивает взаимный эксклюзивный доступ к общему ресурсу с несколькими потоками в Java. Но когда вы сталкиваетесь с примером, как показано ниже, я смущен, это хорошая идея, чтобы он синхронизировался. Я знаю, что критические разделы кода должны быть синхронизированы, и это ключевое слово не должно чрезмерно использоваться или оно влияет на производительность.

public static synchronized List<AClass> sortA(AClass[] aArray) 
{
    List<AClass> aObj = getList(aArray);

    Collections.sort(aObj, new AComparator());

    return aObj;
}

public static synchronized List<AClass> getList(AClass[] anArray) 
{
    //It converts an array to a list and returns
}

Ответ 1

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

Если вместо этого вы запускаете несколько потоков, все вызывающие sortA и передавая ссылку на один и тот же массив, у вас будут проблемы без synchronized, потому что они будут мешать друг другу.

Остерегайтесь, что из примера, что метод getList возвращает новый List из массива, так что даже если потоки передают один и тот же массив, вы получаете разные объекты List. Это вводит в заблуждение. Например, используя Arrays.asList создает List, поддерживаемый данным массивом, но javadoc четко заявляет, что Changes to the returned list "write through" to the array. поэтому будьте осторожны.

Ответ 2

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

В приведенном выше фрагменте кода данных нет. Методы работают на введенном входе и возвращают результат. Если несколько потоков вызывают один из ваших методов, каждый вызов будет иметь свой собственный вход и выход. Следовательно, нет никаких шансов на постоянство в любом месте. Таким образом, ваши методы в приведенном выше фрагменте не должны синхронизироваться.

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

Ответ 3

Ваши статические методы не зависят от какого-либо общего состояния, поэтому не нужно синхронизировать.

Ответ 4

Не существует правила, определенного как использовать синхронизацию, а когда нет, когда вы уверены, что ваш код не будет доступен для одновременных потоков, вы можете избежать использования синхронизированного.

Ответ 5

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

Все в основном должны быть неблокируемыми, поскольку коллекции из пакета concurrency реализованы.

Как и в вашем примере, все вызывающие потоки передают там собственную копию массива, getList не нужно синхронизировать, поэтому метод sortA, поскольку все остальные переменные являются локальными.

Локальные переменные живут в стеке, и каждый поток имеет свой собственный стек, поэтому другие потоки не могут помешать ему.

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

Ответ 6

Я бы не использовал synchronized для однопоточного кода. т.е. когда нет возможности, к которому объект будет доступен несколькими потоками.

Это может показаться очевидным, но ~ 99% StringBuffer, используемое в JDK, может использоваться только одним потоком, может быть заменено на StringBuilder (который не синхронизирован)