Во-первых, элементы экземпляра могут быть потокобезопасными. Достаточно просто убедиться, что статические члены являются поточно-ориентированными, но не предоставляют те же гарантии для членов экземпляров по причинам, которые мы обсуждали ранее.
Во-вторых, конструктор не вызывается в контексте, где более одного потока могут получить доступ к одному экземпляру. Единственная ссылка на вновь созданное исключение ApplicationException в этот момент является локальной для вызывающего метода и, следовательно, видимой только для одного потока. Если два потока одновременно обращаются к методу Throw, у них будет создано два отдельных экземпляра.
Поэтому, хотя он сам по себе не является потокобезопасным, он не используется в контексте, доступном для нескольких потоков, и, следовательно, нет необходимости блокировать его.
Более важный случай:
void MyFunctionOfThreadSafety(string someStr, int someInt, bool someBool)
{
if(someBool)// №1
{
var dict = new Dictionary<string, int>();
dict[someStr] = someInt; // №2
int test = 0;
if(!dict.TryGetValue(someStr, out test))// №3
throw new Exception("really unexpected");
dict[someStr] = test + someInt; // №4
}
}
В этом коде строки, прокомментированные с №1 по №4, - это места, где, если рассматриваемые объекты доступны более чем одному потоку, тогда проблемы безопасности потока могут вызвать проблемы (действительно, все кроме №1 предлагают больше одна точка, в которой потоки могут переключаться, и все становится странным).
Этот код, тем не менее, полностью поточно-ориентирован. Хотя он выполняет несколько потенциально небезопасных действий с объектами, ни один из этих объектов не может быть изменен другим потоком.
someInt
и someBool
- параметры типа значения, которые не были переданы byref
или out
. Поэтому они существуют только в контексте этого метода (и методов, которые он вызывает, если передает их на byref
или out
).
someStr
- это ссылочный тип, передаваемый в качестве параметра, что означает, что он потенциально может также храниться где-то, что может получить другой поток. Однако, поскольку он является неизменным, нет опасности, что другой поток записывает в него (так как никакой поток вообще не может писать в него). Чтения не должны быть защищены от чтения, только от записи (хотя, когда у вас есть чтение и запись, вам может потребоваться заблокировать как чтение, так и запись). Поскольку операции someStr
могут быть прочитаны, это безопасно.
dict
и test
созданы в этом методе, поэтому они безопасны. Если dict
было возвращено из метода, то в качестве изменяемого ссылочного типа он мог бы, если бы он хранился где-то видимым для нескольких потоков, стать проблемой безопасности потока. Но (а) это не было и (б) это не будет проблемой до после это произошло; здесь это потокобезопасно, несмотря ни на что.