簡體   English   中英

在同時調用方法時是否需要同步訪問方法參數和本地?

[英]Do I need to synchronize access the method arguments and locals when calling a method concurrently?

我一直在用靜態類/方法編寫很多代碼,我認為這些代碼將由多個線程同時調用/執行。 所以我在我的方法中做了很多鎖定。 我通常這樣做:

public static class MyThreadsafeMethods {

    private static Object staticLock1 = new Object();
    private static Object staticLock2 = new Object();

    public static string StaticMethod1(string param1, int param2) {
        lock (staticLock1) {
            var _param1 = param1;
            var _param2 = param2;

            //highly confidential business logic here

            return StaticMethod2(_param1, "Integer: " + _param2.ToString());
        }
    }

    public static string StaticMethod2(string param1, string param2) {
        lock (staticLock2) {
            var _param1 = param1;
            var _param2 = param2;

            //truly groundbreaking algorithm here

            return _param1 + " - " + _param2;
        }
    }
}

我想知道兩件事:

1)我以為我需要在“鎖定代碼”中使用我的參數的本地“副本”; 因為如果另一個線程用param1和param2的不同值調用我的方法,那可能會搞砸我的處理。 如果我只使用在鎖定代碼中聲明/實例化的變量(即上例中的_param1和_param2),那么某些東西可以改變param1和param2的值(或者發送對不同對象的引用),我沒關系。 但我需要這樣做嗎? 我是不必要的偏執狂?

2)我已經決定在我需要它之前不想實例化我的鎖對象,因為我的靜態鎖定對象集合正在增長......所以,我現在正在這樣做:

    private static Object staticLock1;

    public static string StaticMethod1(string param1, int param2) {
        lock(staticLock1 = staticLock1 ?? new Object()) {
            (...)
        }
    }

是否有任何理由在我第一次需要時實例化我的鎖定對象是不安全的? 在我的鎖定語句中使用我的鎖定對象上的賦值運算符會不會導致我出現問題或阻止對象被正確鎖定?

  1. 你所擁有的東西根本沒有任何區別 - 在調用之后,參數本身不會改變,所以它什么也沒做。 在你的情況下使用字符串,看到字符串是不可變的是非常安全的。 如果不是這種情況,則傳遞的任何內容都可能在其他地方被更改。 在這種情況下,你必須制作一個真正的副本(即不只是復制參考),

  2. 考慮兩個線程同時到達lock(staticLock1 = staticLock1 ?? new Object())的情況。 他們都可以將staticLock1視為null。 所以沒有那不安全!

您的主要困惑似乎是為了安全地同時安全地調用靜態方法所需的同步。

數據爭用總是會出現,因為多個線程以不同步的方式訪問同一個存儲位置,並且其中至少有一個是編寫器。 這個基本規則足以說明很多並發問題。

調用方法時,參數對每個調用都有不同的存儲位置。 他們是獨立的。 因此,調用相同方法的兩個線程永遠不會競爭訪問方法參數。 因此,您永遠不需要同步對方法參數的訪問。

當地人也是如此。 實際上,參數具有與locals相同的同步屬性。 每次通話都存在。

回答你的第二個問題:這是不安全的,因為兩個線程可能會鎖定不同的對象。 此外,您在多個線程上寫入staticLock1同步。 我已經解釋過這是一場數據競賽。

第一:創建Object實例的開銷非常小。 除非測量顯示您應該這樣做,否則不要擔心。

只需像這樣初始化:

private readonly static object staticLock1 = new Object();

你使用lock語句的方式並不安全。

其次:我在方法中看不到共享數據,所以沒有理由鎖定。

最后:如果設計包含許多靜態函數,我會重新考慮它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM