вопрос о примере книги - параллелизм Java на практике, листинг 4.12 - PullRequest
3 голосов
/ 05 апреля 2010

Я работаю над примером в Java Concurrency на практике и не понимаю, почему в следующем коде необходим безопасный для одновременного контейнера.

Я не вижу, как контейнер состояние "локации" могут быть изменены после строительства; поэтому, поскольку он публикуется через оболочку «unmodifiableMap», мне кажется, что обычного HashMap будет достаточно.

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

Я думаю, что мое замешательство основано на том, в каком именно состоянии находится проблема.

Спасибо !! -Mike

Листинг 4.12, Параллелизм Java на практике, (этот список доступен как .java здесь , а также в форме главы через Google)

///////////// код начала

@ThreadSafe
public class PublishingVehicleTracker {

private final Map<String, SafePoint> locations;
private final Map<String, SafePoint> unmodifiableMap;

public PublishingVehicleTracker(
                        Map<String, SafePoint> locations) {
    this.locations
        = new ConcurrentHashMap<String, SafePoint>(locations);
    this.unmodifiableMap
        = Collections.unmodifiableMap(this.locations);
}

public Map<String, SafePoint> getLocations() {
    return unmodifiableMap;
}

public SafePoint getLocation(String id) {
    return locations.get(id);
}

public void setLocation(String id, int x, int y) {
    if (!locations.containsKey(id))
        throw new IllegalArgumentException(
            "invalid vehicle name: " + id);
    locations.get(id).set(x, y);
  }
}

// монитор защищенного помощника класса

@ThreadSafe
public class SafePoint {

@GuardedBy("this") private int x, y;

private SafePoint(int[] a) { this(a[0], a[1]); }

public SafePoint(SafePoint p) { this(p.get()); }

public SafePoint(int x, int y) {
    this.x = x;
    this.y = y;
}

public synchronized int[] get() {
    return new int[] { x, y };
}

public synchronized void set(int x, int y) {
    this.x = x;
    this.y = y;
}

} * * тысяча двадцать-один

/////////// код конца

Ответы [ 3 ]

4 голосов
/ 06 апреля 2010

Вы правы. Я думаю, что это ошибка в JCiP. Если вы хотите быть уверенным в этом, я предлагаю вам опубликовать его в своем списке рассылки: http://gee.cs.oswego.edu/dl/concurrency-interest

Как вы сказали, карта не изменяется; изменение значения не приводит к "записи" на карту.

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

Вот упрощенная версия (без проверки нуля и т. Д.) Моего кода (в итоге я использовал ImmutableMap из google-collection.):

class Sample {
    private final ImmutableMap<Long, AtomicReference<Stuff>> container;

    Sample(){
        this.container = getMap();
    }

    void setStuff(Long id, Stuff stuff){
        AtomicReference<Stuff> holder = container.get(id);
        holder.set(stuff);
    }
}

Он отлично работал при экстремальных нагрузках в течение длительного времени.

1 голос
/ 08 апреля 2010

@ Цвей, спасибо за предложение - Джо Боубер и Тим Пайерлс (соавторы JCiP) подтвердили, что технически в этом случае будет достаточно обычной хэш-карты. (хотя любой реальный дизайн, вероятно, имел бы дополнительные требования, которые требовали бы одновременной карты)

Причина в том, что основная карта
-транзитивно достижимы из конечного поля
-не изменился с момента публикации через 'getLocations ()' (фактически после ctor он никогда не менялся, но в этом нет необходимости)
- правильно построенный

Джо указал мне на пару очень хороших постов в блоге, объясняющих больше о том, что на самом деле означает неизменяемость Java:

http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html
http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-2.html

Я бы направил туда читателей для полного объяснения.

Спасибо!

1 голос
/ 05 апреля 2010

Метод setLocation действительно изменяет содержимое карты.

Обновление: Я обсудил проблему с коллегой, и в итоге мы пришли к согласию с выводом @Zwei Steinen (+1 ему: -).

Обратите внимание, что помимо того, что он упомянул, видимость также является проблемой. Однако в этом случае карта объявляется final, что гарантирует это.

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