CodeGym /בלוג Java /Random-HE /Multithreading: מה עושות השיטות של מחלקת Thread
John Squirrels
רָמָה
San Francisco

Multithreading: מה עושות השיטות של מחלקת Thread

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

שיטת Thread.start()‎

נתחיל בלחזור על עצמנו. כפי שאתה בוודאי זוכר, אתה יכול ליצור שרשור על ידי כך שהכיתה שלך תירש את Threadהמחלקה ועקוף את run()השיטה. אבל זה לא יתחיל מעצמו, כמובן. לשם כך, אנו קוראים לשיטת האובייקט שלנו start(). ריבוי שרשורים: מה עושות השיטות של מחלקת ה-Thread - 2נזכיר את הדוגמה מהשיעור הקודם:
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
הערה: כדי לפתוח שרשור, עליך לקרוא לשיטה המיוחדתstart()ולא לשיטהrun()! זוהי שגיאה קלה לביצוע, במיוחד כאשר אתה מתחיל ללמוד ריבוי הליכות. בדוגמה שלנו, אם תקרא לשיטהrun()10 פעמים במקוםstart(), תקבל את זה:
public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
תסתכל על התוצאות של התוכנית שלנו: שרשור הוצא לפועל: שרשור-0 שרשור הופעל: שרשור-1 שרשור הופעל: שרשור-2 שרשור הוצא לפועל: שרשור-3 שרשור הוצא לפועל: שרשור-4 השרשור הופעל: אשכול-5 השרשור הופעל: אשכול-6 שרשור בוצע: שרשור-7 שרשור הוצא לפועל: שרשור-8 שרשור הוצא לפועל: שרשור-9 תסתכל על סדר הפלט: הכל מתרחש בסדר מושלם. מוזר, הא? אנחנו לא רגילים לזה, כי אנחנו כבר יודעים שהסדר שבו שרשורים מתחילים ומבוצעים נקבע על ידי אינטלקט מעולה בתוך מערכת ההפעלה שלנו: מתזמן השרשורים. אולי פשוט התמזל מזלנו? כמובן, זה לא עניין של מזל. אתה יכול לאמת זאת על ידי הפעלת התוכנית עוד כמה פעמים. הבעיה היא שלקריאה לשיטה run()ישירות אין שום קשר לריבוי ההליכים. במקרה זה, התוכנית תבוצע על השרשור הראשי, אותו שרשור שמבצע את main()השיטה. זה פשוט מדפיס ברצף 10 שורות על הקונסולה וזהו. 10 שרשורים לא נפתחו. אז, זכרו את זה בעתיד ובדקו את עצמכם כל הזמן. אם אתה רוצה run()לקרוא לשיטה, התקשר ל- start(). בוא נלך רחוק יותר.

שיטת Thread.sleep()

כדי להשהות את ביצוע השרשור הנוכחי לזמן מה, אנו משתמשים בשיטה sleep(). ריבוי שרשורים: מה עושות השיטות של מחלקת ה-Thread - 3השיטה sleep()לוקחת מספר אלפיות שניות כארגומנט, המציין את משך הזמן להרדם את החוט.
public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");

   }
}
פלט קונסולה: - כמה זמן ישנתי? - 3 שניות הערה: השיטה sleep()היא סטטית: היא משינה את השרשור הנוכחי. כלומר, זה שהוצא להורג כרגע. הנה עוד נקודה חשובה: חוט שינה יכול להיקטע. במקרה זה, התוכנית זורקת InterruptedException. נשקול דוגמה להלן. אגב, מה קורה אחרי שהשרשור מתעורר? האם זה ימשיך להתבצע ממש מהמקום שבו הפסיקה? לא. לאחר שרשור מתעורר, כלומר הזמן שעבר כטיעון אל Thread.sleep()עבר, הוא עובר למצב שניתן להפעיל . אבל, זה לא אומר שמתזמן השרשור יריץ אותו. יתכן שהוא ייתן עדיפות לחוט אחר שאינו ישן ולאפשר לחוט שהתעורר הטרי שלנו להמשיך בעבודתו מעט מאוחר יותר. הקפד לזכור את זה: להתעורר לא אומר להמשיך לעבוד מיד!

שיטת Thread.join()

ריבוי שרשורים: מה עושות השיטות של מחלקת ה-Thread - 4השיטה join()משעה את ביצוע השרשור הנוכחי עד לסיום שרשור אחר. אם יש לנו 2 שרשורים, t1ו t2, ואנחנו כותבים
t1.join()
אז t2לא יתחיל עד t1שיסיים את עבודתו. השיטה join()יכולה לשמש כדי להבטיח את סדר הביצוע של חוטים. הבה נבחן כיצד join()השיטה פועלת בדוגמה הבאה:
public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Thread started: " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Thread " + getName() + " is finished.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /* The second thread (t2) will start running only after the first thread (t1)
       is finished (or an exception is thrown) */
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       // The main thread will continue running only after t1 and t2 have finished
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("All threads have finished. The program is finished.");

   }
}
יצרנו ThreadExampleשיעור פשוט. המשימה שלו היא להציג הודעה שהשרשור התחיל, להירדם ל-5 שניות, ואז לבסוף לדווח שהעבודה הושלמה. קלי קלות. ההיגיון העיקרי הוא בכיתה Main. תסתכל על ההערות: אנו משתמשים בשיטה join()כדי לנהל בהצלחה את סדר הביצוע של השרשורים. אם אתה זוכר איך התחלנו את הנושא הזה, סדר הביצוע מטופל על ידי מתזמן השרשור. הוא מפעיל שרשורים לפי שיקול דעתו: בכל פעם בצורה אחרת. כאן אנו משתמשים בשיטה כדי להבטיח שהשרשור t1יתחיל ויבוצע קודם כל, אחר כך t2השרשור, ורק לאחריו ימשיך השרשור הראשי של התוכנית. ממשיך הלאה. בתוכניות אמיתיות, לעתים קרובות תמצא מצבים שבהם תצטרך להפריע לביצוע שרשור. לדוגמה, השרשור שלנו פועל, אבל הוא ממתין לאירוע או מצב מסוים. אם זה קורה, החוט נעצר. זה כנראה יהיה הגיוני אם הייתה איזושהי stop()שיטה. אבל זה לא כל כך פשוט. פעם, ל-Java אכן הייתה Thread.stop()שיטה ואפשרה להפריע לשרשור. אבל זה הוסר מאוחר יותר מספריית Java. אתה יכול למצוא אותו בתיעוד של Oracle ולראות שהוא מסומן כמוצא משימוש . למה? כי זה פשוט עצר את השרשור בלי לעשות שום דבר אחר. לדוגמה, ייתכן שהשרשור עובד עם נתונים ומשנה משהו. ואז באמצע עבודתו היא נקטעה בפתאומיות וללא טקס על ידי stop()השיטה. בלי כיבוי מתאים, גם לא שחרור משאבים, אפילו לא טיפול בשגיאות - לא היה כל זה. אם להגזים מעט, stop()השיטה פשוט הרסה את כל מה שבדרכה. זה היה כמו למשוך את כבל החשמל מהשקע כדי לכבות את המחשב. כן, אתה יכול לקבל את התוצאה הרצויה. אבל כולם יודעים שאחרי כמה שבועות המחשב לא יודה לך על כך שאתה מתייחס אליו. זו הסיבה שהלוגיקה של הפסקת שרשורים השתנתה ב-Java ועכשיו היא משתמשת בשיטה מיוחדת interrupt().

שיטת Thread.interrupt()

מה קורה אם interrupt()השיטה נקראת על שרשור? יש 2 אפשרויות:
  1. אם האובייקט היה במצב המתנה, למשל, עקב שיטות joinאו sleep, ההמתנה תופסק והתוכנית תזרוק InterruptedException.
  2. אם השרשור היה במצב תקין, interruptedהדגל הבוליאני יוגדר על האובייקט.
אבל אנחנו צריכים לבדוק את הערך של הדגל הזה על האובייקט ולסיים נכון את העבודה בעצמנו! לכן Threadלכיתה יש את boolean isInterrupted()השיטה. נחזור לדוגמה השעון שהייתה בשיעור בקורס הבסיסי. מטעמי נוחות, פישטנו אותו מעט:
public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("The thread was interrupted");
               break;
           }
           System.out.println("Tick");
       }
   }
}
במקרה זה, השעון מופעל ומתחיל לתקתק כל שנייה. בשניה העשירית אנו קוטעים את חוט השעון. כפי שאתה כבר יודע, אם השרשור שאנו מנסים להפריע נמצא באחד ממצבי ההמתנה, התוצאה היא InterruptedException. זהו חריג מסומן, כך שנוכל לתפוס אותו בקלות ולבצע את ההיגיון שלנו כדי לסיים את התוכנית. וזה בדיוק מה שעשינו. הנה התוצאה שלנו: Tick Tick Tick Tick Tick Tick Tick Tick Tick השרשור נקטע. זה מסיים את ההקדמה שלנו עם Threadהשיטות החשובות ביותר של הכיתה. בהצלחה!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION