ThreadStatic vs ThreadLocal <T>: chung chung tốt hơn thuộc tính?


94

[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ì?


4
Xem reedcopsey.com/2009/11/12/... - Tôi không thấy điều này đã làm với suy nghĩ mặc dù ...
Jon Skeet

Câu trả lời:


110

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 Fookhở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>.


20
Ngoại trừ có lẽ đó ThreadLocal<T>là có sẵn trong .NET 4 trở lên, và các ThreadStaticthuộc tính cũng có sẵn trong 3,5 và thấp hơn.
Jeroen

2
Và nếu bạn không sử dụng trình khởi tạo để đặt giá trị, mà thay vào đó bạn đang đặt nó vào một thời điểm nào đó sau khi khởi tạo, thì việc sử dụng [ThreadStatic] sẽ rõ ràng hơn về mặt cú pháp.
Nghĩ rằng

9
Và ngoại trừ ThreadLocal<T>dụng cụ IDisposablevà thường buộc bạn phải thực hiện IDisposablelà tốt, mà buộc người gọi của bạn để xử lý bạn và do đó thực hiện IDisposablecũng ...
Stefan Steinegger

4
@StefanSteinegger: Tôi sẽ rất cẩn thận khi sử dụng ThreadLocalhoặc ThreadStaticvớ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.
Jim Mischel,

3
Không nên khai báo trường trong ví dụ static? Xem msdn.microsoft.com/en-us/library/…
entheh

39

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();
    }

nhập mô tả hình ảnh ở đây


14

Ý 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 valuetừng luồng, bao gồm cả luồng chính.

nhập mô tả hình ảnh ở đây

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.


1
Và bài báo đầy đủ có thể được tìm thấy ở đây .
Daniel Dušek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.