سؤال

جئت عبر هذا شرط مناقشة سبب كسر نموذج تأمين الاختيار المزدوج في جافا. هو النموذج صالح ل .NET (على وجه الخصوص، C #)، إذا تم الإعلان عن المتغيرات volatile?

هل كانت مفيدة؟

المحلول

تنفيذ نمط Singleton في C # يتحدث عن هذه المشكلة في الإصدار الثالث.

انها تقول:

إن إجراء متغير المثيل المتغير يمكن أن يجعله يعمل، وكذلك مكالمات حاجز الذاكرة الصريحة، على الرغم من أنه في الحالة الأخيرة حتى الخبراء لا يستطيعون الموافقة بالضبط الحواجز المطلوبة بالضبط. أميل إلى محاولة تجنب المواقف التي لا يوافق فيها الخبراء على صواب وما هو الخطأ!

يبدو أن المؤلف يعني أن القفل المزدوج أقل عرضة للعمل من الاستراتيجيات الأخرى، وبالتالي لا ينبغي استخدامه.

نصائح أخرى

يعمل تسجيل الوصول المزدوج الآن يعمل الآن في Java بالإضافة إلى C # (تغير نموذج ذاكرة Java وهذا هو أحد الآثار). ومع ذلك، عليك الحصول عليه بالضبط الصحيح. إذا كنت تعثث الأشياء قليلا، فقد تنتهي صلاحية تفقد سلامة الخيط.

كما ذكرت إجابات أخرى، إذا كنت تنفذ نمط singleton هناك طرق أفضل بكثير للقيام بذلك. شخصيا، إذا كنت في موقف حيث يجب أن أختر بين قفل مزدوج فحصه و "قفل في كل مرة"، سأذهب لإحباطه في كل مرة حتى حصلت على دليل حقيقي على أنه كان يسبب عنق الزجاجة. عندما يتعلق الأمر بخيوط، فإن نمط بسيط ومن الواضح أن صحيح يستحق الكثير.

.NET 4.0 لديه نوع جديد: Lazy<T> التي تسلب أي قلق بشأن الحصول على نمط الخطأ. انها جزء من المهمة الجديدة المكتبة الموازية.

راجع مركز ديف الحوسبة MSDN الموازي: http://msdn.microsoft.com/en-us/concurrency/default.aspx.

راجع للشغل، هناك Backport (أعتقد أنه غير مدعوم) ل .NET 3.5 SP1 المتاحة هنا.

ملاحظة مما كانت عليه في Java (وعلى الأرجح في .NET أيضا)، فإن قفل مزدوج تم فحصه لتهيئة المفروغة غير ضروري تماما وكذلك مكسورة. نظرا لأن الفصول الدراسية لا تتم تهيئتها حتى يتم استخدامها لأول مرة، فإن التهيئة الكسول المرغوبة قد تحقق بالفعل من خلال هذا؛

private static Singleton instance = new Singleton();

ما لم يكن فئة Singleton الخاصة بك تحتوي على أغراض مثل الثوابت التي قد يتم الوصول إليها قبل استخدام مثيل Singleton لأول مرة، فهذا كل ما عليك القيام به.

لا أحصل على السبب في أن كل الناس يقولون أن قفل الاختيار المزدوج هو نمط سيء، ولكن لا تتكيف مع التعليمات البرمجية لجعله يعمل بشكل صحيح. في رأيي، يجب أن يعمل هذا الرمز أدناه على ما يرام.

إذا كان شخص ما قد يقول لي إذا كان هذا القانون يعاني من المشكلة المذكورة في مقالة كاميرون، يرجى القيام بذلك.

public sealed class Singleton {
    static Singleton instance = null;
    static readonly object padlock = new object();

    Singleton() {
    }

    public static Singleton Instance {
        get {
            if (instance != null) {
                return instance;
            }

            lock (padlock) {
                if (instance != null) {
                    return instance;
                }

                tempInstance = new Singleton();

                // initialize the object with data

                instance = tempInstance;
            }
            return instance;
        }
    }
}

لقد حصلت على قفل مزدوج الاستخدام للعمل باستخدام منطقي (أي استخدام بدائي لتجنب التهيئة الكسول):

Singleton باستخدام منطقي لا يعمل. لا يتم ضمان ترتيب العمليات كما شوهد بين المواضيع المختلفة إلا إذا ذهبت من خلال حاجز الذاكرة. بمعنى آخر، كما يظهر من الخيط الثاني،created = true قد يتم تنفيذه من قبل instance= new Singleton();

لا أفهم تماما سبب وجود مجموعة من أنماط التنفيذ على قفل مزدوج فحص (على ما يبدو للعمل حول خصوصيات الترجمة في لغات مختلفة). تعرض مقالة Wikipedia حول هذا الموضوع الطريقة السذاجة والطرق الممكنة لحل المشكلة، ولكن لا شيء بسيط مثل هذا (في C #):

public class Foo
{
  static Foo _singleton = null;
  static object _singletonLock = new object();

  public static Foo Singleton
  {
    get
    {
      if ( _singleton == null )
        lock ( _singletonLock )
          if ( _singleton == null )
          {
            Foo foo = new Foo();

            // Do possibly lengthy initialization,
            // but make sure the initialization
            // chain doesn't invoke Foo.Singleton.
            foo.Initialize();

            // _singleton remains null until
            // object construction is done.
            _singleton = foo;
          }
      return _singleton;
    }
  }

في Java، كنت تستخدم متزامنة () بدلا من القفل ()، ولكنها في الأساس نفس الفكرة. إذا كان هناك عدم تناسق ممكن عند تعيين حقل Singleton، فلماذا لا تستخدم متغيرا محليا محليا أولا ثم قم بتعيين حقل Singleton في اللحظة الممكنة الأخيرة قبل الخروج من القسم الحرج؟ هل فاتني شيء؟

هناك حجة بواسطة @ Michael-Borgwardt أنه في C # و Java الحقل الثابت يحصل تهيئة فقط مرة واحدة على الاستخدام الأول، ولكن الذي - التي السلوك هو لغة محددة. وقد استخدمت هذا النمط بشكل متكرر للتهيئة الكسول لممتلكات المجموعة (مثل المستخدمين).

لقد حصلت على قفل مزدوج الاستخدام للعمل باستخدام منطقي (أي استخدام بدائي لتجنب التهيئة الكسول):

private static Singleton instance;
private static boolean created;
public static Singleton getInstance() {
    if (!created) {
        synchronized (Singleton.class) {
            if (!created) {
                instance = new Singleton();
                created = true;
            }
        }
    }
    return instance;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top