Объявите объект как синхронизированный в Java - PullRequest
3 голосов
/ 21 августа 2011

Можно ли объявлять объект и синхронизироваться, избегая одновременного доступа к нему двух потоков?или мне нужно было бы объявить синхронизированный блок в каждой точке, где используется объект?

Я пытался, но невозможно использовать синхронизированный таким образом:

    public synchronized Vector<MyObject> myvector;

Заранее спасибо

Ответы [ 7 ]

2 голосов
/ 21 августа 2011

Если вы использовали какую-то другую коллекцию, в классе Коллекции есть средства для синхронизации коллекции.

List<MyObject> myList = Collections.synchronizedList( new ArrayList<MyObject> );
2 голосов
/ 21 августа 2011

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

Начиная с платформы Java 2 v1.2, этот класс был модернизирован до реализовать List, чтобы он стал частью коллекции Java фреймворк. В отличие от новых реализаций коллекции, Vector является синхронизируется.

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

1 голос
/ 21 августа 2011

Насколько я знаю, это ключевое слово в этом месте недопустимо. Однако вы можете использовать объекты, которые являются потокобезопасными, такие как Векторы, или вы можете использовать синхронизированные (o) {...} кодовые блоки.

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

0 голосов
/ 21 августа 2011

Объявление синхронизированных полей работает только с примитивными типами в Java.Нельзя синхронизировать объекты, просто объявив их ссылки синхронизированными - представьте, что произойдет, если вы попытаетесь сделать две разные ссылки на один и тот же объект.

Таким образом, вы можете понять, почему следующий синтаксис не разрешен:

public ArrayList<Object> myList = new ArrayList<Object>();

public synchronized ArrayList<Object> mySyncedList = myList; 

//is the original list now synchronized or not?

Хотя у вас есть несколько решений для этого:

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

public class MyCollection {
    public synchronized void addObject(Object a) {
        ...
    }
}

В частности, класс Vector внутренне синхронизирован и в вашемНапример, не нужно больше синхронизировать.Однако ваши собственные классы и многие классы Java не будут иметь такой гарантии.

2) Если Объект является классом библиотеки Java, может быть способ получить синхронизированную копию с использованием функциональных возможностей библиотеки.Чаще всего это используется для списков:

public List<Object> mySyncedList = Collections.synchronizedList(myList);

//pass around mySyncedList instead of myList to guarantee synchronization

3) Если объект не синхронизирован изнутри, и не предоставляет возможность получить его синхронизированную копию, и у вас нет возможности редактироватьИсходный исходный код, у вас нет выбора, кроме как синхронизировать код, который изменяет объект:

synchronized(myList) {
    myList.add(next);
}

Осторожно, хотя: даже если ваш собственный код синхронизирован, если вы публикуете ссылку на этот объект снаружитогда любой программист, использующий ваши классы, также должен будет синхронизировать доступ к этому объекту!

0 голосов
/ 21 августа 2011

Vector является синхронизированной коллекцией, что означает, что ее состояние инкапсулировано, а все методы синхронизированы.

Тем не менее, Vector, будучи поточно-ориентированным, не гарантирует последовательных результатов для составных действий (проверьте, существуют ли элементы, затем что-то делаете), так что да - вам придется защищать весь доступ к экземпляру вектора такой же замок (внутренний или иной). Такая политика иногда называется «блокировкой на стороне клиента».

Но даже в этом случае "полная синхронизация" может быть затруднена в случае Vector (использование итераторов и т. Д.).

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

Для справки - Пакет java.util.concurrent

0 голосов
/ 21 августа 2011

Вам необходимо выполнить синхронизацию с помощью шаблона делегирования:

private volatile Vector<MyObject> myObjects;

public synchronized boolean addMyObject(MyObject o) {
    return myObjects.add(o);
}

// etc for other methods of Vector that you want to expose.

Обратите внимание, что синхронизированный метод доступа не сделает этого:

private volatile Vector<MyObject> myObjects;

public synchronized Vector<MyObject> getMyObjects() {
    return myObjects;
}

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

0 голосов
/ 21 августа 2011

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

Если первое, то ключевое слово volatile подходит ближе всего к тому, что вам нужно.Это не совсем то же самое, что synchronized в методах / блоках, но переменная volatile действует так, как будто она синхронизируется сама по себе.

Если последнее, то вам не нужноМетоды устаревшего Vector класса уже сами по себе synchronized.

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