logo

מחזור חיים של חוט (מצבי חוט)

ב-Java, שרשור תמיד קיים בכל אחד מהמצבים הבאים. מדינות אלו הן:

  1. חָדָשׁ
  2. פָּעִיל
  3. חסום / ממתין
  4. המתנה מתוזמנת
  5. הסתיים

הסבר על מצבי חוט שונים

חָדָשׁ: בכל פעם שנוצר שרשור חדש, הוא תמיד במצב החדש. עבור שרשור במצב החדש, הקוד עדיין לא הופעל ולכן לא החל בביצועו.

פָּעִיל: כאשר שרשור מפעיל את שיטת start() הוא עובר מהמצב החדש למצב הפעיל. המצב הפעיל מכיל בתוכו שני מצבים: האחד הוא ניתן לריצה , והשני הוא רץ .

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

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

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

כאשר השרשור הראשי מפעיל את שיטת join() אז, נאמר שהשרשור הראשי נמצא במצב המתנה. לאחר מכן, השרשור הראשי ממתין לשרשורי הילדים שישלימו את המשימות שלהם. כאשר השרשורים הצאצאים משלימים את עבודתם, נשלחת הודעה לשרשור הראשי, אשר שוב מעביר את השרשור מהמתנה למצב פעיל.

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

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

הסתיים: שרשור מגיע למצב סיום בגלל הסיבות הבאות:

  • כאשר שרשור סיים את תפקידו, אז הוא קיים או מסתיים כרגיל.
  • סיום חריג:זה מתרחש כאשר כמה אירועים חריגים כגון חריגה לא מטופלת או תקלת פילוח.

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

התרשים הבא מציג את המצבים השונים המעורבים במחזור החיים של חוט.

מחזור החיים של חוט Java

יישום מדינות שרשור

ב-Java, אפשר לקבל את המצב הנוכחי של שרשור באמצעות ה- Thread.getState() שיטה. ה Java.lang.Thread.State class של Java מספק את הקבועים ENUM כדי לייצג את מצב השרשור. הקבועים הללו הם:

ג'אווה דומה
 public static final Thread.State NEW 

הוא מייצג את המצב הראשון של חוט שהוא המצב החדש.

 public static final Thread.State RUNNABLE 

זה מייצג את המצב הניתן להרצה. זה אומר שרשור ממתין בתור להפעלה.

 public static final Thread.State BLOCKED 

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

 public static final Thread.State WAITING 

זה מייצג את מצב ההמתנה. שרשור יעבור למצב זה כאשר הוא יפעיל את שיטת Object.wait() או שיטת Thread.join() ללא פסק זמן. שרשור במצב המתנה ממתין לשרשור אחר שישלים את המשימה שלו.

 public static final Thread.State TIMED_WAITING 

הוא מייצג את מצב ההמתנה המתוזמן. ההבדל העיקרי בין המתנה להמתנה מתוזמנת הוא אילוץ הזמן. להמתנה אין מגבלת זמן, ואילו להמתנה מתוזמנת יש מגבלת זמן. שרשור המפעיל את השיטה הבאה מגיע למצב המתנה מתוזמן.

  • לִישׁוֹן
  • הצטרף עם פסק זמן
  • לחכות עם פסק זמן
  • פארק עד
  • parkNanos
 public static final Thread.State TERMINATED 

זה מייצג את המצב הסופי של שרשור שנסגר או מת. שרשור שהסתיים אומר שהוא השלים את ביצועו.

תוכנית Java להדגמת מצבי שרשור

תוכנית Java הבאה מציגה חלק מהמצבים של שרשור שהוגדר לעיל.

שם קובץ: ThreadState.java

 // ABC class implements the interface Runnable class ABC implements Runnable { public void run() { // try-catch block try { // moving thread t2 to the state timed waiting Thread.sleep(100); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println('The state of thread t1 while it invoked the method join() on thread t2 -'+ ThreadState.t1.getState()); // try-catch block try { Thread.sleep(200); } catch (InterruptedException ie) { ie.printStackTrace(); } } } // ThreadState class implements the interface Runnable public class ThreadState implements Runnable { public static Thread t1; public static ThreadState obj; // main method public static void main(String argvs[]) { // creating an object of the class ThreadState obj = new ThreadState(); t1 = new Thread(obj); // thread t1 is spawned // The thread t1 is currently in the NEW state. System.out.println('The state of thread t1 after spawning it - ' + t1.getState()); // invoking the start() method on // the thread t1 t1.start(); // thread t1 is moved to the Runnable state System.out.println('The state of thread t1 after invoking the method start() on it - ' + t1.getState()); } public void run() { ABC myObj = new ABC(); Thread t2 = new Thread(myObj); // thread t2 is created and is currently in the NEW state. System.out.println('The state of thread t2 after spawning it - '+ t2.getState()); t2.start(); // thread t2 is moved to the runnable state System.out.println('the state of thread t2 after calling the method start() on it - ' + t2.getState()); // try-catch block for the smooth flow of the program try { // moving the thread t1 to the state timed waiting Thread.sleep(200); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println('The state of thread t2 after invoking the method sleep() on it - '+ t2.getState() ); // try-catch block for the smooth flow of the program try { // waiting for thread t2 to complete its execution t2.join(); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println('The state of thread t2 when it has completed it's execution - ' + t2.getState()); } } 

תְפוּקָה:

 The state of thread t1 after spawning it - NEW The state of thread t1 after invoking the method start() on it - RUNNABLE The state of thread t2 after spawning it - NEW the state of thread t2 after calling the method start() on it - RUNNABLE The state of thread t1 while it invoked the method join() on thread t2 -TIMED_WAITING The state of thread t2 after invoking the method sleep() on it - TIMED_WAITING The state of thread t2 when it has completed it's execution - TERMINATED 

הֶסבֵּר: בכל פעם שאנחנו מולידים שרשור חדש, השרשור הזה מגיע למצב החדש. כאשר השיטה start() מופעלת על שרשור, מתזמן השרשור מעביר את השרשור למצב הניתן להרצה. בכל פעם שמתודה join() מופעלת על מופע שרשור כלשהו, ​​השרשור הנוכחי שמבצע את ההצהרה הזו צריך לחכות עד שהשרשור הזה יסיים את ביצועו, כלומר להעביר את השרשור למצב הסתיים. לכן, לפני שהצהרת ההדפסה הסופית מודפסת על הקונסולה, התוכנה מפעילה את השיטה join() ב-thread t2, מה שגורם ל-thread t1 להמתין בזמן שה-thread t2 מסיים את ביצועו וכך, ה-thread t2 יגיע למצב הסתיים או מת. . Thread t1 עובר למצב המתנה מכיוון שהוא ממתין ל-thread t2 לסיים את ביצועו מכיוון שהוא הפעיל את השיטה join() על thread t2.