Использование ключевого слова volatile не сделает ваш код поточно-ориентированным в этом примере. Ключевое слово volatile обычно используется для того, чтобы при чтении или записи значения переменной (т. Е. Поля класса) последнее значение для этой переменной либо считывалось из основной памяти, либо записывалось прямо в основную память, а не читалось из кеша (например, регистр процессора) например. Ключевое слово volatile - это способ сказать «не использовать оптимизацию кэширования с этим общим полем», и устраняет проблему, когда потоки могут использовать локальные копии поля и не видеть обновления друг друга.
В вашем случае значение myclass на самом деле не обновляется (т.е. вы не переназначаете myclass), так что volatile бесполезно для вас, и это не обновление переменной myclass, которую вы действительно хотите сделать thread- в любом случае безопасно в этом случае.
Если вы хотите сделать обновление реального класса поточно-безопасным, тогда использование «блокировки» вокруг «Добавить» и «Очистить» является прямой альтернативой. Это гарантирует, что только один поток одновременно может выполнять эти операции (которые обновляют внутреннее состояние myclass), и поэтому не должен выполняться параллельно.
Замок можно использовать следующим образом:
private readonly object syncObj = new object();
private readonly myclass = new myclass();
......
lock (syncObj)
{
myclass.Add(...)
}
lock (syncObj)
{
myclass.Clear(..)
}
Вам также необходимо добавить блокировку вокруг любого кода, который считывает состояние, которое обновляется с помощью «Добавить», если это так, хотя это не отображается в вашем примере кода.
При первом написании многопоточного кода может быть неочевидно, зачем вам нужна блокировка при добавлении в коллекцию. Если мы возьмем List или ArrayList в качестве примера, тогда возникает проблема, так как внутренне эти коллекции используют Array в качестве резервного хранилища и будут динамически «увеличивать» этот Array (т. Е. Создавая новый больший массив и копируя старое содержимое), как определенно мощности встречаются при вызове Add. Все это происходит внутри и требует обслуживания этого массива и переменных, таких как текущий размер коллекции (а не длина фактического массива, который может быть больше). Поэтому добавление в коллекцию может включать несколько шагов, если внутренний массив должен расти. При использовании нескольких потоков небезопасным образом, несколько потоков могут косвенно вызывать рост при добавлении и, таким образом, растоптывать все обновления друг друга. Помимо проблемы одновременного добавления нескольких потоков, существует также проблема, связанная с тем, что другой поток может пытаться прочитать коллекцию , в то время как внутреннее состояние изменяется. Использование блокировок гарантирует, что подобные операции выполняются без вмешательства других потоков.