עדיפויות לגבי threads
כפי שכבר הזכרנו, דרגת העדיפות של thread יכולה להיות מותאמת לו ביחס לסדר העדיפות של שאר ה threads. דרגת העדיפות של thread מסוים אומרת ל scheduler (מתזמן) של ג'אווה מתי הthread צריך לרוץ בהתחשב בשאר ה threads.
מכיוון שלכל המחשבים יש מספר מוגבל של מעבדים, לא כל הthreads רצים בו זמנית תמיד. לרוב המחשבים יש מעבד אחד בלבד כך ש threads בדרך כלל רצים אחד אחרי השני באופן כזה שהם יוצרים רושם כאילו הם פועלים בו-זמנית.
זמן-הריצה של ג'אווה תומך באלגוריתם תזמון (scheduling algorithm) הידוע בשם fixed priority scheduling (תזמון על פי סדר עדיפות קבוע) האלגוריתם הזה מתזמן threads בהסתמך על סדר העדיפות שלהם ביחס ל threads אחרים הניתנים להרצה.
thread של ג'אווה יורש את דרגת העדיפות שלו מה thread שיצר אותו. באפשרותך לשנות את דרגת העדיפות של thread לאחר יצירתו מתי שתרצה באמצעות מתודת setPriority. קבועי ה- integer הבאים מוגדרים במחלקה Thread :
· MIN _ PRIORITY
· MAX _ PRIORITY
כל ערךinteger בין שני הקצוות האלה, כולל הקצוות עצמם, יכול להיקבע כדרגת העדיפות של thread מסוים. ככל שערך ה integer גבוה יותר - דרגת העדיפות גבוהה יותר. כששני threads או יותר מוכנים להפעלה ואחד ממשאבי המערכת נעשה זמין להפעלת thread, מערכת זמן-הריצה בוחרת את הthread הניתן להרצה הנמצא בעדיפות הגבוהה ביותר.
לפי Canpione & Walrath :
"רק כשה thread 'נעצר', 'מוותר' (yields) , או נעשה Not Runnable , מתחיל |
בנוסף, לדבריהם: " אם שני threads שיש להם אותה עדיפות ממתינים למעבד, המתזמן scheduler)) בוחר להריץ אחד מהם בשיטת
ה “round – robin”, ה thread שייבחר ירוץ עד שיתממש אחד מהתנאים הבאים:
· thread בדרגת עדיפות גבוהה יותר נעשה Runnable (ניתן להרצה)
· הוא 'מוותר' (yields) או שמתודת ה run() שלו יוצאת (exits).
· במערכות התומכות בהקצאת זמנים (time-slicing) , הזמן שהוקצה לו פג.
תזמון על פי זכות קדימה (Preemptive Scheduling)
אם thread שהוא בעל העדיפות הגבוהה ביותר מכל הthreads הניתנים להרצה האחרים נהפך לניתן-להרצה(Runnable) , מערכת זמן-הריצה תיקח את מקומו של ה thread שכבר רץ משיקולי זכות קדימה, ותבחר להפעיל את ה thread החדש שיש לו עדיפות גבוהה יותר.
Threads אנוכיים (Selfish Threads)
במערכות שלא מספקות הקצאת זמנים (time slicing) לגבי threads שהם בעדיפות שווה, יכול אחד מהthreads לרכוש ולהשתלט על כל המעבד, תוך שהוא בהכרח מונע מ threads אחרים שיש להם אותה דרגת עדיפות את ההזדמנות לפעול.
הקצאת זמנים (Time Slicing)
במערכות מסוימות, למשל ב Windows 95, מוטמעת האסטרטגיה של הקצאת הזמנים = time-slicing, כדי למנוע מ thread 'אנוכי' לשלול מ threads אחרים שיש להם אותה עדיפות את היכולת לרוץ. לדברי Campione & Walrath :
"מערכת שיש לה מנגנון להקצאת זמנים מחלקת את המעבד ליחידות זמן ונותנת באופן איטרטיבי יחידת זמן לריצה לכל אחד מאותם threads הנמצאים באותה דרגת העדיפות הגבוהה ביותר. המערכת להקצאת זמנים עוברת שוב ושוב בין ה threads הנמצאים כולם בעדיפות הגבוהה ביותר, ונותנת לכל אחד מהם פרק זמן מסוים עד שאחד מהם, או יותר, מסיים, או עד שתופס את מקומם thread שיש לו עדיפות גבוהה יותר. שים לב לכך שהקצאת זמנים אינה יכולה להיות ערובה לתכיפות או לסדר שבו יתוזמנו ה threads לרוץ". |
כמו כן, מציינים Campione & Walrath: "מערכת זמן-הריצה של ג'אווה אינו מיישם (ולכן גם לא מהווה ערובה ל-) הקצאת זמנים.
על כל פנים, מערכות מסוימות בהן ניתן להריץ את ג'אווה, כן תומכות בהקצאת זמנים. לא כדאי שתוכניות הג'אווה שלך יסתמכו על הקצאת זמנים כיוון שזה יכול להביא לתוצאות שונות במערכות השונות.
המתודה yield()
thread יכול 'לוותר מרצונו' על המעבד על ידי קריאה למתודה yield(). מתודה זו נותנת ל threads אחרים שיש להם אותה עדיפות הזדמנות לרוץ.
אם אין threads נוספים שיש להם אותה עדיפות במצב ה “Runnable” - מתעלמים מהוויתור.
Daemon Threads
כפי שכבר אמרנו, a Daemon Thread הוא thread ששייך יותר למערכת מאשר ל processשייצר אותו. Daemon Threads משרתים לעיתים קרובות threads אחרים במערכת.
כל thread של ג'אווה יכול להיות daemon thread. בכדי לציין ש thread הוא Daemon קרא למתודה setDaemon עם הארגומנט true.
בכדי לקבוע האם thread מסוים הוא daemon השתמש במתודת ה accessor - isDaemon
קבוצת Thread
זו הפעם הראשונה שאנו מזכירים את הנושא של קבוצות thread ואנו לא נקדיש לו זמן רב:
כל הthreads משתייכים לקבוצת thread.
מחלקת ה ThreadGroup , שהיא אחד ממרכיבי חבילת java.lang , מגדירה ומיישמת את היכולות של קבוצת threads שיש ביניהם קשר.
קבוצות של threads מאפשרות לך לקבץ threads שונים כאובייקט אחד ולתמרן אותם כקבוצה ולא כל אחד בנפרד.
לדוגמא, אתה יכול להשעות (suspend) את כל ה threads בקבוצה .
קיימות מגוון מתודות לתמרון threads כקבוצה.
כשבונים thread חדש, שמים אותו בקבוצת thread.
ניתן :
· לתת למערכת לשים את ה thread בקבוצה של ברירת מחדל.
· או לקבוע באופן מפורש את הקבוצה של ה thread החדש.
אינך יכול להעביר thread לקבוצה חדשה לאחר שה thread נוצר.
קבוצת ה thread מסוג 'ברירת מחדל' (The Default Thread Group)
אם אתה לא מגדיר את קבוצתו בפונקציה הבונה, המערכת ממקמת thread חדש באותה הקבוצה של הthread שיצר אותו.
כשמתחיל יישום של ג'אווה המערכת יוצרת ThreadGroup הנקראת “main”.
אם לא הוגדר אחרת, כל הthreads החדשים הופכים להיות שייכים לקבוצת ה thread הנקראת “main”.
ש לכך ראיה כבר בפלט של תוכנית ההדגמה (sample program)הראשונה של השיעור הזה שמטעמי נוחות אנו חוזרים עליה להלן. עדיין לא דנו בפורמט של הפלט הזה:
Thread[threadA,5,main]Thread[threadB,5,main]Thread[main,5,main] |
. כשאתה משתמש ב –
System.out.println(Thread.currentThread()) |
כדי להציג מידע על thread , כמו במקרה של תוכנית ההדגמה, מה שאתה מקבל הוא:
- שם הthread
- דרגת העדיפות שלו
- שם הקבוצה אליה הוא שייך
במקרה של תוכנית ההדגמה שלנו, כל שלושת ה threads השתייכו לקבוצת main כפי שניתן לראות לעיל. המחלקה Thread מספקת פונקציות בונות שבהם אתה יכול להשתמש בכדי להגדיר קבוצה
ל threadכשאתה יוצר לו מופעים.
אתה יכול לדעת את הקבוצה שאליה שייך thread על ידי קריאה למתודת ה getThreadGroup שלו. ברגע שיש לך את המידע הזה, ישנן מתודות שמאפשרות לך לחקור את הקבוצה בשביל מידע נוסף, כמו למשל, איזה threads אחרים משתייכים לקבוצה. למחלקה ThreadGroup יש מגוון יכולות שלא נדון בהן כאן. בהחלט כדאי לך ללמוד על היכולות האלה.