Простой вопрос по синхронизации Java - PullRequest
2 голосов
/ 31 марта 2011

Я бы хотел перебрать java List, используя цикл по старинке (int i ...), поскольку для данной итерации i и цикла я хочу получить доступ к нескольким элементам, относящимся к i. Тогда я не могу использовать для (Object o: objects) ни итератор списка.

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

Я пытался

synchronized(path.getPoints()){
    for (int i = 0; i < path.getPoints().size(); i++){
        ...
    }
}

где путь - объект, содержащий список, а также

synchronized(path){
    for (int i = 0; i < path.getPoints().size(); i++){
        ...
    }
}

а также

synchronized(this){
    for (int i = 0; i < path.getPoints().size(); i++){
        ...
    }
}

где «this» - это средство визуализации, которое хочет отобразить путь без проблем с синхронизацией.

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

Martin

Ответы [ 6 ]

7 голосов
/ 31 марта 2011

Как я могу убедиться, что нет другого кода можно получить доступ к списку, пока я выполняет это?

Убедившись, что весь другой код также синхронизируется на одном и том же объекте. synchronized(path.getPoints()) - лучший выбор. Для getPoints() может быть хорошей идеей вернуть список, заключенный в Collections.synchronizedList() - тогда вам не нужно явно синхронизировать простые вызовы get() или add(), но вам все равно нужна синхронизация для итерации.

Complicated? Да уж. Вот почему многопоточное программирование с разделяемой памятью считается очень сложным.

1 голос
/ 31 марта 2011

Вы можете полностью избежать синхронизации, используя метод копирования при записи.С ним связаны расходы, но они могут быть приемлемы для вас: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

0 голосов
/ 31 марта 2011

Я бы посоветовал вам написать это как.

List<Point> points = path.getPoints()
synchronized(points){
    for (Point point: points){
        ...
    }
}

Это гарантирует, что getPoints () не возвращает что-то другое и упрощает код IMHO.

Я бы также использовал предложение @Michaelsлибо синхронизации каждый раз, когда осуществляется доступ к getPoints (), либо сделайте его Collectons.synchronizedList () или потокобезопасным списком, например CopyOnWriteArrayList ()

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

0 голосов
/ 31 марта 2011

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

0 голосов
/ 31 марта 2011

«synchronized (this)» (где «this» - ваш рендерер) гарантирует, что ни один другой поток не сможет запустить тот же рендерер одновременно; однако другие потоки могут получить доступ к списку и объекту «путь».

0 голосов
/ 31 марта 2011

Вы можете синхронизировать path.getPoints () и возвращать копию списка точек (или, возможно, массив). Тогда вам не нужно синхронизировать данные при выполнении итерации. Если точки являются частными, вы можете легко убедиться, что все методы в Path, которые обращаются к ним, также синхронизированы.

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