מבוא: The Singleton Pattern in Multi-Threaded Engineering Applications

דפוס Singleton הוא אחד דפוסי עיצוב הנפוצים ביותר בהנדסת תוכנה.זה מבטיח כי בכיתה יש רק מקרה אחד ומספק נקודת גישה גלובלית של גישה לדוגמה זו.ביישומים חד-פעמיים, יישום יחידון הוא פשוט: להפוך את בונה פרטי, לספק שיטה סטטית מחזירה מקרה אחד שנוצרת באופן להוט או עצלן.

מאמר זה בוחן את השגיאות הנפוצות ביותר מפתחי לעשות בעת יישום דפוס ה- Singleton בסביבות מרובות-הנקרא, מסביר את הסיבות הבסיסיות, ומספק קבוצה מקיפה של שיטות ותבניות הטובות ביותר כדי למנוע מהם.זה כולל גם דוגמאות קוד מעשי ב- Java, עם התייחסות לדפוסים מקבילים ב- C++ ו- C#, וממליץ על משאבים חיצוניים לקריאה נוספת.

טעויות נפוצות ב Singleton Implementation

אפילו מפתחים מנוסים יכולים ליפול למלכודת כאשר הם מבצעים טייפונים במערכות במקביל. להלן הם השגיאות השכיחות ביותר, כל אחד מהם עם הסבר מדוע הם מסוכנים.

לא להפוך את בונה פרטי

הבסיס של כל אחד מהטון הוא בונה פרטי המונעת מיידיות חיצונית.אם הבונים נגיש (ציבור, מוגן או חבילה-פרטי), כל חוט יכול ליצור מקרה חדש, לשבור את החוזה של הטון.בקוד רב-המוכר, זה יכול לקרות ללא פגע כאשר מעמד הוא מארגן מחדש, או כאשר נראהת הבנייה צפויה בטעות, או כאשר המעמד הוא subtoned (בדרך כלל מוגדר שימוש מיידי), אם כי אתה חייב להיות מוגן או באופן קבוע, או באופן קבוע, או באופן קבוע, או לא ברור, אם אתה יכול להיות מוגן (בדרך כלל, או אחרת, או תמיכה).

2.הכישלון לשמור על בטיחות

בסביבה אחת, עצלן פשוט עובד בסדר:

public class Singleton {
 private static Singleton instance;
 private Singleton() {}
 public static Singleton getInstance() {
 if (instance == null) {
 instance = new Singleton();
 }
 return instance;
 }
}

אך ביישום רב-הנקרא, שני חוטים או יותר יכולים להיכנס במקביל לבדוק (FLT:1) לפני כל חוט יצר את המקרה.כל חוט ממשיך ליצור משלו FLT:2 להתנגד, מפר את התבנית.

שימוש ב-Lazy Preization ללא סינכרוניזציה נכונה

אפילו מפתחים שמכירים בצורך בבטיחות חוט לעתים קרובות מוסיפים סינכרוניזציה בתמימות.לדוגמה, מסנכרנים את כל שיטת ה-FLT:3 פועלת אך מציגים צוואר בקבוק ביצועים:

public static synchronized Singleton getInstance() { ... }

כל קריאה לתרחישים של תוכן גבוה, זה מעל 5 לרכוש ומשחרר את המנעול, גם לאחר שהדוגמה כבר נוצר.בתרחישים של תוכן גבוה, זה מעל הראש יכול לחלחל באופן חמור דרך הפלט.הגישה הטובה יותר היא להשתמש ב-FLT:0double-checked LockingFLT:1 (שלא מתמקד להלן), אבל אפילו דפוס זה יש פגמים אם לא ייושם כראוי.

4.Overing SynSyncization

(ה) ,(ה) , ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇

5.הבטן:0volatileveph 1

בשפות כמו Java, C# ו- C++ (עם FLT:10), מילת המפתח של ההרחבה:0volatileFLT:1 (או שווה ערך) חיונית לחשיפה נכונה בקוד רב-הנקרא, ללא זה, המדר או CPU עשוי לתקן הוראות, שינויים שנעשו על ידי חוט אחד לא ניתן לראות אחד לשני.

Best Practices for Edit-Safe Singleton Implementation

כדי להימנע מהמכשולים האלה, בצע אסטרטגיות מוכחות אלה.כל גישה מתייחסת לבטיחות חוט, ביצועים ופשטות.

בונה פרטי ואינסטינקט סטטי

ללא קשר לאסטרטגיה הראשונית של ההבנות, על הבונים להיות פרטי.הדוגמה של הטון צריך להיות מאוחסן בשדה סטטי.אל לחשוף את הבניין בכל דרך שהיא, ולשקול לעשות את הכיתה FLT:12 ב Java (או LT:13 ב C#) כדי למנוע תת-מעמד.

השתמש בבלוקים הסינכרון רק כאשר יש צורך

עבור עצלות, דפוס נעילה כפול נבדק להפחית סינכרוניזציה מעל ראש:

public class Singleton {
 private static volatile Singleton instance;

 private Singleton() {}

 public static Singleton getInstance() {
 Singleton result = instance; // Local variable for performance
 if (result == null) {
 synchronized (Singleton.class) {
 result = instance;
 if (result == null) {
 instance = result = new Singleton();
 }
 }
 }
 return result;
 }
}

בקוד זה, הסימון (FLT:15) מחוץ לבלוק הסינכרון נמנע מהמנעול מעל הראש כאשר המקרה כבר קיים.הבדיקה הפנימית מבטיחה שרק חוט אחד יוצר את המקרה. מילת המפתח של FLT:16 מונעת הוראה מחדש ומבטיחה כי המשימה של CLT:17 הוא גלוי לחלוטין חוטים אחרים.

אם הטון תמיד נחוץ ויצירה היא זולה, מיפוי להוט הוא הגישה הפשוטה ביותר לבטיחות חוט:

public class Singleton {
 private static final Singleton INSTANCE = new Singleton();

 private Singleton() {}

 public static Singleton getInstance() {
 return INSTANCE;
 }
}

טעינה בכיתה היא מסונכרנת מטבעה על ידי JVM, כך שאין צורך בתיאום נוסף.עם זאת, זה יוצר את המקרה בזמן טעינה בכיתה, אשר עשוי להיות בלתי רצוי במערכות מחסומות משאבים או כאשר הטון תלוי בתצורה של זמן ריצה כי עדיין לא זמין.

Static Holder Pattern (Initialization-on-Dei)

דפוס זה משלב אמפתיה עצלנית עם בטיחות חוט ללא סינכרוניזציה מפורשת:

public class Singleton {
 private Singleton() {}

 private static class Holder {
 static final Singleton INSTANCE = new Singleton();
 }

 public static Singleton getInstance() {
 return Holder.INSTANCE;
 }
}

שיעור ה-FLT:21 טעון רק כאשר נקרא הראשון, ו- JVM מבטיח פרסום בטוח של השדה סטטי במהלך טעינה בכיתה.זה נחשב נרחב לפתרון האלגנטי ביותר עבור ג'אווה רווקות.

Enum-based Singleton (Java)

יהושע בלוך (בקיצור:0) ממליץ להשתמש ב-AfLT:0.

public enum Singleton {
 INSTANCE;

 // methods and fields
}

קבועי אנום הם ללא כל ספק ; ושפת Java מבטיחה כי מקרים enum נוצרים רק פעם אחת, אפילו תחת התקפות ויזואליזציה או השתקפות.זה הן בטוח והן תמציתיות. עם זאת, enums לא יכול להאריך שיעורים (רק יישום ממשקים), כך שהם אינם מתאימים לכל מקרי השימוש.

תבניות שוות ערך ב C++ ו- C#

ב C++, ה- 0 (Meyer's SingletonFLT) 1:1 (החלומת סטטית נמוכה) הוא בטוח חוטי-שקט מאז C++11:

Singleton& getInstance() {
 static Singleton instance;
 return instance;
}

ב- C#, שיעור ה-FLT:26 מספק עצלות עצלות מבוססת חוט:

public class Singleton {
 private static readonly Lazy<Singleton> _lazy =
 new Lazy<Singleton>(() => new Singleton());

 public static Singleton Instance => _lazy.Value;
}

בדיקות ושיקולים ביישומים הנדסיים

ביישומים הנדסיים, דפוס הטון לעתים קרובות מצליח משאבים משותפים כמו נהגי חומרה, הגדרות תצורה, בריכות חוט, או שירותי כניסה.בדיקה של סינגלים כאלה במבחנים רב-הנקראים דורש תכנון זהיר.

  • (הופנה מהדף ההרחבה) (הופנה מהדף ההרחבה:0) ,(ה) ,(ה) לעשות סטומונים (ה) שיטה שהוגדרה רק במבחנים) או על ידי הזרקת התלויות באמצעות ממשק. יישומים מודרניים רבים נמנעים מסינגלונים לחלוטין לטובת מסגרות הזרקת התלות שעושות ניהול מחזור חיים.
  • (ב) ,0) ,התאמת למערכות אמת או ⁇ גבוהה: למדוד את ראש הסינכרון.במקרים מסוימים, יחיד ללא מנעול באמצעות FLT:29 (C#) או FLT:30 (C++) עשוי להיות מוצדק.
  • (FLT:0) מערכות מחוסמות (FLT:103) דורשות מטומטמים להיות ייחודיים בתהליך, לא על פני תהליכים.אם אתה צריך סינגלטון רחב כל-התחבורה, להשתמש בתיאום חיצוני (למשל, מסד נתונים, שומר גן החיות, או בחירות מנהיג).
  • (ב) ,0) השתקפות וסידוריות (הראשונה) יכולים לשבור את הטון (FLT:31) בסידור Java, ולמנוע מחיקה רפלקטיבית על ידי זריקת יוצא מן הכלל אם FLT:32 כבר מוגדר.

מסקנה

דפוס ה- Singleton נותר כלי יקר בתיבת הכלים של מהנדס התוכנה, אך יישוםו בסביבות מרובות-הנקרא דורש תשומת לב קפדנית לפרטים.על ידי הבנה והימנעות מטעויות נפוצות - כגון לא-פרטיות, סינכרוניזציה חסרה, שימוש לא הולם, שימוש לא הולם, וסנכרון יתר - משפרי ביצועים יכולים לייצר סינגלים חזקים, גבוהים ביצועים.

לצורך מחקר נוסף, התייחס למשאבים הבאים:

  • שם הסרטון:0Wikipedia: Singleton PatternFreaLT
  • (ב) ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
  • [ה]ה': [ה]: [ה], ה'התעלל" [ה], הוא ה'הבאה], הוא ה'[דרוש מקור]
  • (ב) .0.10 Singleton PatternFLT:1

בסופו של דבר, יישום הטון הטוב ביותר הוא זה שהוא פשוט ביותר עבור דרישות שלך.כאשר ספק, מעדיף ראשונית להוטה או דפוס בעל סטטי, ותמיד לכתוב בדיקות יחידות במקביל כדי לאמת את הנכונות תחת תוכן.