[ThreadStatic]
được xác định bằng cách sử dụng thuộc tính trong khi ThreadLocal<T>
sử dụng chung. Tại sao các giải pháp thiết kế khác nhau được chọn? Ưu điểm và nhược điểm của việc sử dụng thuộc tính chung trong trường hợp này là gì?
[ThreadStatic]
được xác định bằng cách sử dụng thuộc tính trong khi ThreadLocal<T>
sử dụng chung. Tại sao các giải pháp thiết kế khác nhau được chọn? Ưu điểm và nhược điểm của việc sử dụng thuộc tính chung trong trường hợp này là gì?
Câu trả lời:
Một điều gì đó mà bài đăng trên blog ghi nhận trong các bình luận không rõ ràng, nhưng tôi thấy rất quan trọng, đó là [ThreadStatic]
nó không tự động khởi tạo mọi thứ cho mọi chủ đề. Ví dụ: giả sử bạn có cái này:
[ThreadStatic]
private static int Foo = 42;
Luồng đầu tiên sử dụng điều này sẽ thấy được Foo
khởi tạo thành 42
. Nhưng các chủ đề tiếp theo sẽ không. Bộ khởi tạo chỉ hoạt động cho luồng đầu tiên. Vì vậy, bạn sẽ phải viết mã để kiểm tra xem nó có được khởi tạo hay không.
ThreadLocal<T>
giải quyết vấn đề đó bằng cách cho phép bạn cung cấp một chức năng khởi tạo (như blog của Reed cho thấy) được chạy trước lần đầu tiên mục được truy cập.
Theo tôi, không có lợi thế khi sử dụng [ThreadStatic]
thay thế ThreadLocal<T>
.
ThreadLocal<T>
là có sẵn trong .NET 4 trở lên, và các ThreadStatic
thuộc tính cũng có sẵn trong 3,5 và thấp hơn.
ThreadLocal<T>
dụng cụ IDisposable
và thường buộc bạn phải thực hiện IDisposable
là tốt, mà buộc người gọi của bạn để xử lý bạn và do đó thực hiện IDisposable
cũng ...
ThreadLocal
hoặc ThreadStatic
với các luồng hồ bơi. Những giá trị đó sẽ vẫn tồn tại trong toàn bộ vòng đời của pool thread, không chỉ cho nhiệm vụ mà bạn giao nó. Điều đó có thể khiến bạn gặp rắc rối theo một số cách khá không rõ ràng. Xem stackoverflow.com/questions/561518/… và các câu hỏi tương tự để biết thêm thông tin.
static
? Xem msdn.microsoft.com/en-us/library/…
Chỉ khởi tạo ThreadStatic trên luồng đầu tiên, Khởi tạo ThreadLocal cho mỗi luồng. Dưới đây là minh chứng đơn giản:
public static ThreadLocal<int> _threadlocal =
new ThreadLocal<int>(() =>
{
return Thread.CurrentThread.ManagedThreadId;
});
public static void Main()
{
new Thread(() =>
{
for (int x = 0; x < _threadlocal.Value; x++)
{
Console.WriteLine("First Thread: {0}", x);
}
}).Start();
new Thread(() =>
{
for (int x = 0; x < _threadlocal.Value; x++)
{
Console.WriteLine("Second Thread: {0}", x);
}
}).Start();
Console.ReadKey();
}
Ý tưởng chính đằng sau ThreadStatic là duy trì một bản sao riêng biệt của biến cho mỗi luồng .
class Program
{
[ThreadStatic]
static int value = 10;
static void Main(string[] args)
{
value = 25;
Task t1 = Task.Run(() =>
{
value++;
Console.WriteLine("T1: " + value);
});
Task t2 = Task.Run(() =>
{
value++;
Console.WriteLine("T2: " + value);
});
Task t3 = Task.Run(() =>
{
value++;
Console.WriteLine("T3: " + value);
});
Console.WriteLine("Main Thread : " + value);
Task.WaitAll(t1, t2, t3);
Console.ReadKey();
}
}
Trong đoạn mã trên, chúng tôi có một bản sao riêng của value
từng luồng, bao gồm cả luồng chính.
Vì vậy, một biến ThreadStatic sẽ được khởi tạo thành giá trị mặc định của nó trên các luồng khác ngoại trừ luồng mà nó được tạo.
Nếu chúng ta muốn khởi tạo biến trên mỗi luồng theo cách riêng của mình, hãy sử dụng ThreadLocal.