מדוע לא להתחיל חוט בבנאי?

1. סקירה כללית

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

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

2. פרסום ובריחה

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

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

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

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

3. בריחה עם חוטים

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

מחלקה ציבורית LoggerRunnable מיישמת Runnable {public LoggerRunnable () {Thread thread = Thread new (this); // זה בורח מ- thread.start (); } @Override הפעלה בטלנית ציבורית () {System.out.println ("התחיל ..."); }}

כאן אנו מעבירים במפורש את זֶה התייחסות ל פְּתִיל בַּנַאִי. לָכֵן, החוט החדש שהתחיל אולי יוכל לראות את האובייקט הסוגר לפני השלמת בנייתו המלאה. בהקשרים מקבילים, הדבר עלול לגרום לבאגים עדינים.

אפשר גם להעביר את זֶה התייחסות במרומז:

מחלקה ציבורית ImplicitEscape {public ImplicitEscape () {Thread t = Thread new () {@Override public void run () {System.out.println ("התחיל ..."); }}; t.start (); }}

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

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

3.1. חלופות

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

מחלקה ציבורית SafePublication מיישמת Runnable {private thread thread thread; SafePublication ציבורי () {thread = אשכול חדש (זה); } @Override הפעלה בטלנית ציבורית () {System.out.println ("התחיל ..."); } התחלה בטלנית ציבורית () {thread.start (); }} ;:

כפי שמוצג לעיל, אנו עדיין מפרסמים את זֶה התייחסות ל פְּתִיל. עם זאת, הפעם, אנו מתחילים את השרשור לאחר שהבנאי חוזר:

פרסום SafePublication = SafePublication חדש (); publication.start ();

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

4. מסקנה

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

מידע מפורט יותר על הפרסום והבריחה בג'אווה ניתן למצוא בספר Java Concurrency in Practice.

כרגיל, כל הדוגמאות זמינות ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found