Джава.Сериализация объектов в многопоточной среде - PullRequest
4 голосов
/ 20 июня 2010

У меня есть объект, внутреннее изменяемое состояние которого постоянно обновляется одним или несколькими потоками.Объект синхронизирован, и цель состоит в том, чтобы периодически сохранять его состояние (посредством сериализации) из еще одного потока:

public class Counter implements Serializable {
    private int dogCount;
    private int catCount;

    public synchronized void updateFromDogThread( int count ) { 
        dogCount = count; 
    }

    public synchronized void updateFromCatThread( int count ) { 
        catCount = count; 
    }
}

Вопросы:

  • Безопасна ли сериализация в этом случае?
  • Как это работает под капотом?То есть, будет ли ObjectOutputStream выполнять блок сериализации до тех пор, пока ни один из потоков больше не будет работать с Counter?
  • Что если синхронизация Counter не использует встроенную блокировку, но некоторыедругой замок?

Ответы [ 3 ]

3 голосов
/ 25 апреля 2012

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

В вашем случае вы хотите, чтобы сериализация была синхронизирована с объектом. Поэтому все, что вам нужно сделать, это добавить ключевое слово synchronized в метод. Вы все еще можете использовать реализацию по умолчанию defaultWriteObject:

private synchronized void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject();
}
2 голосов
/ 20 июня 2010
  • Безопасна ли в этом случае сериализация?

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

  • Как это работает под капотом? То есть будет ли ObjectOutputStream выполнять блок сериализации до тех пор, пока никакие потоки больше не будут работать с Counter?

ObjectOutputStream не блокируется под капотом. Это зависит от приложения, если это необходимо.

  • Что если в синхронизации счетчика используется не внутренняя блокировка, а какая-то другая блокировка?

Тогда вашему приложению также потребуется использовать эту другую блокировку для блокировки обновлений во время сериализации.

Если состояние, которое вы сериализуете, просто состоит из состояния одного объекта с двумя полями, то конфликт блокировки и детализация не должны быть проблемой. Но если объект (ы) сложен, тогда конфликт блокировки может быть проблематичным, так же как и проблема получения блокировок без риска тупика. Этот сценарий потребует тщательного проектирования.

2 голосов
/ 20 июня 2010

Это небезопасно, но относительно легко сделать это так:

synchronized (counter) {
    out.writeObject(counter);
}

Как вы заметили, объект заблокирован произвольно, так как механизм сериализации узнает, как получить соответствующую блокировку.Хуже того, порядок сериализации и объектного графа также совершенно произвольный, поэтому любая попытка блокировки часто приводит к тупикам.Даже с решением, описанным выше, вы выполняете сложную операцию в пределах блокировки, поэтому будьте осторожны с тупиками.

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