thread | Java מתקדם

Transcription

thread | Java מתקדם
‫קורס ‪ Java‬מתקדם‬
‫‪'Thread‬ים‬
‫קרן כליף‬
2 ©Keren Kalif | ‫ מתקדם‬Java | thread
...‫למקרה ואנחנו עדיין לא מכירים‬
http://qph.is.quoracdn.net/main-qimg-e0c9dafb319150b6c6d9816047ed9eae?convert_to_webp=true
3 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫תיאום ציפיות מהקורס‬
http://www.1stwebdesigner.com/wp-content/uploads/2011/10/tan_lines_of_a_programmer2.jpg
4 ©Keren Kalif | ‫ מתקדם‬Java | thread
:‫ביחידה זו נלמד‬
‫ ותכונותיו‬Thread
Runnable ‫הממשק‬
‫'ים‬thread ‫מצבים של‬
deadlock -‫ ו‬racing :‫סינכרון תהליכים‬
‫סמפורים‬
Condition+Lock ‫מוניטור ע"י‬
ArrayBlockingQueue
ExecuterService ‫'ים ע"י‬thread -‫הגבלת מספר ה‬
Callable ‫ ע"י הממשק‬thread -‫קבלת ערך מ‬
CountDownLatch -‫ ו‬CyclicBarrier :‫'ים‬thread ‫המתנה לכמות מסויימת של‬
‫אובייקט אנונימי‬
‫אלגוריתמי נעילה‬












‫‪ Java | thread‬מתקדם | ‪5 ©Keren Kalif‬‬
‫תהליכים (‪'Thread‬ים)‬
‫‪‬‬
‫עד היום כל התוכניות שלנו רצו בתהליך אחד‬
‫‪o‬‬
‫כלומר‪ ,‬התוכנית לא הסתיימה עד אשר ה‪ main -‬סיים לרוץ‪ ,‬והפעולות בוצעו אחת אחרי‪-‬‬
‫השניה‪ ,‬באופן סינכרוני‬
‫‪‬‬
‫ביחידה זו נראה כיצד ניתן להריץ כמה פעולות בו‪-‬זמנית‬
‫‪‬‬
‫‪ – Thread‬אובייקט אשר מבצע פעולה באופן אסינכרוני‬
‫‪‬‬
‫בעזרת מנגנון זה התוכנית הראשית (‪ )process‬תוכל להריץ כמה פעולות‬
‫(‪ )thread‬במקביל‪ :‬למשל גם שעון מתחלף‪ ,‬גם הורדת קובץ וגם אינטראקציה עם‬
‫המשתמש‬
‫‪ Java | thread‬מתקדם | ‪6 ©Keren Kalif‬‬
‫דוגמא לתוכנית עם ‪'Thread‬ים‬
‫ניתן לראות בפלט שהפונקציות רצו "יחד"‬
‫‪ Java | thread‬מתקדם | ‪7 ©Keren Kalif‬‬
‫דוגמא למוטיבציה‬
‫המוטיבציה‪ :‬כאשר יש פעולות שלוקחות‬
‫הרבה זמן ולא רוצים שהתוכנית "תתקע"‬
‫השליטה חוזרת ל‪ main -‬רק‬
‫לאחר שהפונקציה הסתיימה‬
‫השליטה חוזרת ל‪-‬‬
‫‪ main‬באופן מיידי‬
‫‪ Java | thread‬מתקדם | ‪8 ©Keren Kalif‬‬
‫כיצד מריצים ‪thread‬‬
‫יש לרשת מהמחלקה ‪Thread‬‬
‫ולדרוס את השיטה ‪run‬‬
‫ב‪ main -‬נייצר אובייקט ממחלקה שיורשת מ‪-‬‬
‫‪ Thread‬ונפעיל את השיטה ‪ ,start‬המריצה‬
‫את הקוד בתהליך נפרד ואסינכרוני‬
‫הפעלה באופן ישיר של השיטה ‪ run‬תפעיל‬
‫אותה באופן רגיל (סינכרוני ובאותו תהליך)‬
‫‪ Java | thread‬מתקדם | ‪9 ©Keren Kalif‬‬
‫מופעים מרובים‬
‫‪‬‬
‫יתכן בתוכנית מחלקת ‪ thread‬אחת עם מופעים רבים‪ .‬כל מופע יטפל בבקשה‬
‫שונה באמצעות קוד זהה‪:‬‬
‫‪o‬‬
‫‪‬‬
‫למשל ‪ thread‬המטפל ברישום לקוחות חדשים‪ .‬בהחלט ניתן לטפל ברישום כמה לקוחות‬
‫בו‪-‬זמנית‪.‬‬
‫מחלקות ‪ thread‬שונות שרצות במקביל וכל אחת מבצעת משהו שונה‪:‬‬
‫‪o‬‬
‫הורדת קבצים‪ ,‬תקשורת מול אתר מרוחק‪ ,‬טיפול בלקוחות וכד'‬
‫‪ Java | thread‬מתקדם | ‪10 ©Keren Kalif‬‬
‫מימוש ‪Runnable‬‬
‫‪‬‬
‫בשפת ‪ JAVA‬הרי ניתן לרשת ממחלקה אחת בלבד‬
‫‪‬‬
‫בצורה הנוכחית‪ ,‬אם נרצה שמחלקה מסויימת תפעל ב‪ thread -‬נפרד אין לנו‬
‫אפשרות‪ ,‬במקרה הצורך‪ ,‬לרשת ממחלקה נוספת‬
‫‪‬‬
‫לכן נממש את הממשק ‪Runnable‬‬
‫‪ Java | thread‬מתקדם | ‪11 ©Keren Kalif‬‬
‫דוגמא‬
‫נייצר משתנה מטיפוס ‪ Runnable‬ונייצר ‪Thread‬‬
‫המקבל כפרמטר משתנה מטיפוס הממשק‬
‫‪ Java | thread‬מתקדם | ‪12 ©Keren Kalif‬‬
‫אובייקט אנונימי‬
‫יצירת אובייקט זמני מטיפוס‬
‫‪ Runnable‬ומימוש השיטה ‪run‬‬
‫‪ Java | thread‬מתקדם | ‪13 ©Keren Kalif‬‬
‫אובייקט אנונימי המשתמש במשתנה חיצוני‬
‫על מנת לגשת למשתנה מחוץ לאובייקט‬
‫האנונימי‪ ,‬יש להגדירו כ‪final -‬‬
‫‪ Java | thread‬מתקדם | ‪14 ©Keren Kalif‬‬
‫מיפוי הזיכרון‬
‫‪‬‬
‫כאשר מריצים תוכנית ‪ main‬למעשה ישנו תהליך ראשי (‪ )process‬עם משאבים‬
‫יחודיים‪ ,‬ובפרט מרחב זיכרון‬
‫‪‬‬
‫בתוך התהליך המרכזי יש לפחות ‪ thread‬אחד‬
‫‪‬‬
‫‪ thread‬גם נקרא ‪light-weight process‬‬
‫‪‬‬
‫כל ה‪'thread -‬ים באותו ‪ process‬חולקים את המשאבים של ה‪process -‬‬
‫שממנו נוצרו‬
‫‪o‬‬
‫בניגוד ל‪'process -‬ים שאינם חולקים זיכרון‬
15 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫'ים‬thread -‫ מורכב מ‬process ‫כמעט כל‬
‫‪ Java | thread‬מתקדם | ‪16 ©Keren Kalif‬‬
‫‪)1( priority‬‬
‫‪‬‬
‫לכל ‪ thread‬יש עדיפות מ‪ 1 -‬עד ‪ .10‬ב"מ היא ‪ .5‬ככל שהעדיפות יותר גבוהה כך‬
‫ה‪ thread -‬יועדף בעת ההרצה‬
‫העדיפות של ה‪-‬‬
‫‪ thread‬הראשי‬
‫ערך ב"מ‪ .‬כלומר פקודה‬
‫זו כרגע מיותרת‪.‬‬
‫העדיפות של ה‪-‬‬
‫‪ thread‬שיצרתי‬
‫בגלל שלשני ה‪'thread -‬ים עדיפות‬
‫זהה‪ ,‬ניתן לראות שהם רצו במקביל‬
‫‪ Java | thread‬מתקדם | ‪17 ©Keren Kalif‬‬
‫מתן ערך עדיפות נמוך‬
‫ניתן לראות שהגלל של‪ thread -‬יש עדיפות‬
‫נמוכה הוא רץ אחרי ה‪ thread -‬הראשי‬
‫‪ Java | thread‬מתקדם | ‪18 ©Keren Kalif‬‬
‫מתן ערך עדיפות גבוה‬
‫ניתן לראות שהגלל של‪ thread -‬יש עדיפות‬
‫גבוהה‪ ,‬כאשר הוא נכנס לפעולה הוא רץ יותר זמן‬
19 ©Keren Kalif | ‫ מתקדם‬Java | thread
thread ‫מידע על‬
thread -‫שם ה‬
‫עדיפות‬
thread -‫שם ב"מ ל‬
process -‫שם ה‬
‫‪ Java | thread‬מתקדם | ‪20 ©Keren Kalif‬‬
‫מוטיבציה ל‪join -‬‬
‫נגיע לשורה זו לפני שה‪-‬‬
‫‪'thread‬ים יסיימו את פעולתם‬
‫‪ Java | thread‬מתקדם | ‪21 ©Keren Kalif‬‬
‫שימוש ב‪join -‬‬
‫נגיע לשורה זו רק אחרי שה‪-‬‬
‫‪'thread‬ים יסיימו את פעולתם‬
‫‪ Java | thread‬מתקדם | ‪22 ©Keren Kalif‬‬
‫כך לא נעצור ‪thread‬‬
‫בצורה זו הורגים את ה‪thread -‬‬
‫אפילו אם לא סיים את פעולתו‪...‬‬
23 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫כך כן נעצור אותו‬
thread -‫ה‬
‫‪ Java | thread‬מתקדם | ‪24 ©Keren Kalif‬‬
‫המתודה ‪interrupt‬‬
‫(‪)1‬‬
‫נגיע לפה אם ה‪thread -‬‬
‫יופסק ע"י ‪interrupt‬‬
‫נשים לב שה‪ thread -‬אינו חייב‬
‫להסתיים בעקבות השימוש ב‪interrupt -‬‬
‫‪ Java | thread‬מתקדם | ‪25 ©Keren Kalif‬‬
‫המתודה ‪interrupt‬‬
‫(‪)2‬‬
‫ממתינה לסיום מקסימום שניה‬
‫הפסקת פעולת ה‪ thread -‬ע"י ‪interrupt‬‬
‫גרועה כמו ‪ ,stop‬גם תהייה‬
‫‪ deprecated‬מתישהו‬
‫האם ה‪thread -‬‬
‫עדיין פעיל‬
‫‪ Java | thread‬מתקדם | ‪26 ©Keren Kalif‬‬
‫מצבים של ‪thread‬‬
‫יצירת משתנה‬
‫מטיפוס ‪thread‬‬
‫מערכת ההפעלה קובעת מתי‬
‫ה‪ thread -‬יקבל זמן ריצה‬
‫הפעלת השיטה ‪start‬‬
‫מעבירה את ה‪thread -‬‬
‫למצב המוכן לפעולה‬
‫ה‪ thread -‬יכול‬
‫להשהות את פעולתו‬
‫ה‪ thread -‬מסיים‬
‫את פעולתו‬
‫התרשים נלקח מ‪:‬‬
‫‪http://www.roseindia.net/java/thread/life-cycle-of-threads.shtml‬‬
27 ©Keren Kalif | ‫ מתקדם‬Java | thread
runnable ‫ אינו‬thread -‫מצבים שונים בהם ה‬
‫ מרדים את עצמו לזמן מסויים‬:Sleeping
‫ אחר יסתיים‬thread -‫ מחכה ש‬:Blocked for Join Completion
‫ מחכה למשאב‬:Blocked for I/O
‫ אחר‬thread -‫ מחכה להתרעה מ‬:Waiting for Notification
‫ אחר ישחרר נעילה‬thread -‫ מחכה ש‬:Blocked for Lock Acquisition
:‫התרשים נלקח מ‬
http://www.roseindia.net/java/thread/life-cycle-of-threads.shtml
‫‪ Java | thread‬מתקדם | ‪28 ©Keren Kalif‬‬
‫דוגמאות למעבר בין ‪sleep/runnable/run‬‬
‫באמצעות ‪ sleep‬נגרום לתוכנית "לנוח"‪ ,‬ולא‬
‫בלולאת ‪ for‬התופסת את זמן ה‪.CPU -‬‬
‫ניתן לראות מעבר לתהליך אחר‪.‬‬
‫‪ Java | thread‬מתקדם | ‪29 ©Keren Kalif‬‬
‫סינכרון תהליכים ‪ -‬הבעיה‬
‫ניתן לראות ש‪ Thread-1 -‬התחיל את פעולתו‪ ,‬והיא כנראה‬
‫הופסקה באמצע‪ :‬הערך לפני ההגדלה הינו ‪ 2‬ואחריה ‪8‬‬
‫‪ Java | thread‬מתקדם | ‪30 ©Keren Kalif‬‬
‫סינכרון תהליכים – הפלט הרצוי‬
‫ניתן לראות שריצת השיטה ‪ run‬עבור כל‬
‫אוביקט לא הופסקה באמצע (ערך ה‪-‬‬
‫‪ counter‬לפני ואחרי ההגדלה עוקב)‬
‫כדי שרצף הפקודות בשיטה ‪ run‬לא יקטעו‬
‫באמצע‪ ,‬יש להגדיר אותם כקטע קוד קריטי‬
‫‪ Java | thread‬מתקדם | ‪31 ©Keren Kalif‬‬
‫פתרון‬
‫התכונה ‪theMutex‬‬
‫משותפת לכל המופעים‬
‫הגדרת הקוד שבבלוק כקטע‬
‫קריטי‪ ,‬ולכן לא יקטע באמצע‬
‫מאחר ולא ניתן לבצע נעילה על אותו אובייקט בו"ז‪ ,‬כל ‪ thread‬שיגיע ל‪-‬‬
‫‪ run‬יאלץ לחכות שהקטע הקריטי יסתיים‪ ,‬עד אשר הנעילה תהייה בידיו‪.‬‬
‫‪ Java | thread‬מתקדם | ‪32 ©Keren Kalif‬‬
‫תרגיל‬
‫‪‬‬
‫יש לדמות מערכת של שדה תעופה‪:‬‬
‫‪o‬‬
‫לכל מטוס ‪ 3‬מצבים‪ :‬המראה‪ ,‬טיסה‬
‫ונחיתה‬
‫‪o‬‬
‫רק מטוס אחד יכול להיות בהמראה או‬
‫בנחיתה ברגע נתון בשדה"ת‬
‫‪o‬‬
‫יש לסגור את שדה התעופה לאחר שכל‬
‫המטוסים סיימו לנחות‬
‫‪o‬‬
‫יש להקפיד על מודולוריות וחוקי תכנות‬
‫של ‪OOP‬‬
‫הנחיות‪ :‬יש להשתמש‬
‫במנגנון של ‪synchronized‬‬
‫הפתרון ב‪exe1_airport -‬‬
‫‪ Java | thread‬מתקדם | ‪33 ©Keren Kalif‬‬
‫‪ wait‬ו‪notify -‬‬
‫‪‬‬
‫לעיתים נרצה ש‪ thread -‬מסויים ישהה את פעולתו עד אשר ‪ thread‬אחר יבצע‬
‫פעולה מסויימת‬
‫‪‬‬
‫ניתן להגדיר ל‪ thread -‬להיכנס למצב ‪ wait‬שיופסק לאחר ש‪ thread -‬אחר ישלח‬
‫את ההודעה ‪notify‬‬
‫‪‬‬
‫שימושי לצורך סינכרון בין תהליכים‬
‫‪‬‬
‫דוגמא‪:‬‬
‫‪o‬‬
‫אני מכינה עוגה וחסר לי קמח‬
‫‪o‬‬
‫אני ארצה להשהות את תהליך ההכנה עד אשר יביאו לי קמח‬
‫‪o‬‬
‫אני ארצה שיודיעו לי כשהקמח הגיע כדי שאוכל להמשיך לעבוד‬
‫‪ Java | thread‬מתקדם | ‪34 ©Keren Kalif‬‬
‫דוגמא‪ :‬המחלקות (‪)1‬‬
‫פקודת ‪ wait‬תמיד תהייה עטופת בבלוק‬
‫‪ synchronized‬עם האובייקט שמחכה‪.‬‬
‫הפעלת השיטה ‪ notify‬על אובייקט זה תסיים‬
‫את פעולת ה‪.wait -‬‬
‫‪ Java | thread‬מתקדם | ‪35 ©Keren Kalif‬‬
‫דוגמא‪ :‬המחלקות (‪)2‬‬
‫מחזיקה כפרמטר את האובייקט‬
‫שצריך "להעיר" מ‪wait -‬‬
‫את הפעולה ‪ notify‬נפעיל על האובייקט שאותו נרצה להעיר‪.‬‬
‫יש לעטוף פקודה זו בבלוק ‪ synchronized‬על האובייקט‬
‫שאותו נעיר‪ ,‬אחרת תתקבל החריגה‬
‫‪IllegalMonitorStateException‬‬
‫‪ Java | thread‬מתקדם | ‪36 ©Keren Kalif‬‬
‫דוגמא‪ :‬ה‪main -‬‬
‫הקישור עבור הסינכרון‬
‫בין ‪ 2‬ה‪'thread -‬ים‬
‫‪ Java | thread‬מתקדם | ‪37 ©Keren Kalif‬‬
‫בלוק או שיטת ‪synchronized‬‬
‫כאשר האובייקט לסינכרון הוא האובייקט המפעיל (‪ ,)this‬ניתן‬
‫להגדיר את כל השיטה כ‪.synchronized -‬‬
‫אופציה זו פחות עדיפה כי אז קטע הנעילה יותר גדול‪ ,‬ונעדיף למקד‬
‫אותו רק לקטע הקוד הקריטי‪.‬‬
‫‪ Java | thread‬מתקדם | ‪38 ©Keren Kalif‬‬
‫מה קורה למשאב הקריטי בזמן ‪)1( ?wait‬‬
‫כאשר אנחנו בתוך ‪ wait‬המשאב הקריטי משתחרר‬
‫עד אשר ה‪ wait -‬ישתחרר באמצעות ‪notify‬‬
‫‪ Java | thread‬מתקדם | ‪39 ©Keren Kalif‬‬
‫מה קורה למשאב הקריטי בזמן ‪)2( ?wait‬‬
‫נשים לב מתי מהתודה ‪ foo‬מופעלת‬
‫‪ Java | thread‬מתקדם | ‪40 ©Keren Kalif‬‬
‫תרגיל‬
‫‪‬‬
‫יש לדמות מערכת של שדה תעופה‪:‬‬
‫‪o‬‬
‫לכל מטוס ‪ 3‬מצבים‪ :‬המראה‪ ,‬טיסה‬
‫ונחיתה‬
‫‪o‬‬
‫רק מטוס אחד יכול להיות בהמראה או‬
‫בנחיתה ברגע נתון בשדה"ת‬
‫‪o‬‬
‫יש לסגור את שדה התעופה לאחר שכל‬
‫המטוסים סיימו לנחות‬
‫הנחיות‪ :‬הפעם אין לבצע נעילה על שדה"ת‪ ,‬אלא לבצע ‪ wait‬כאשר מחכים למסלול‬
‫בשדה התעופה‪ .‬אחריות השדה ליידע את מי שמחכה כאשר המסלול מתפנה‪.‬‬
‫הפתרון ב‪exe2_airport -‬‬
‫‪ Java | thread‬מתקדם | ‪41 ©Keren Kalif‬‬
‫בעיות בעבודה עם ‪'thread‬ים‬
‫‪‬‬
‫‪ – Racing‬כאשר התוצאה של פעולה מסויימת תלויה בתזמון פעולה ב‪thread -‬‬
‫אחר‪ ,‬תלות במשאב משותף‪ .‬אם אין סינכרון יכולה להיווצר בעיה‪.‬‬
‫‪o‬‬
‫לדוגמא‪ :‬מדור משאבי אנוש מעדכן את ערך המשכורות ומחלקת שכר צריכה להנפיק את‬
‫המשכורות‪ .‬אם מחלקת השכר תנפיק את המשכורות לפני העדכון של משאבי האנוש‬
‫תהייה בעיה‪.‬‬
‫‪‬‬
‫‪ – Starving‬כאשר ‪ thread‬מסויים אינו מקבל זמן לריצה ע"י ה‪ .CPU -‬יכול‬
‫לקרות בגלל בעיה בעדיפויות של ה‪'thread -‬ים‪.‬‬
‫‪‬‬
‫‪ – Deadlock‬כאשר ‪'thread 2‬ים אינם יכולים להמשיך בפעילותם מאחר וכל‬
‫אחד ממתין לשני (למשל בעיית אגו‪ :‬אני לא אתקשר אליך עד אשר אתה תתקשר‬
‫אליי‪ ,‬וההיפך‪)...‬‬
‫‪ Java | thread‬מתקדם | ‪42 ©Keren Kalif‬‬
‫דוגמא ל‪racing -‬‬
‫שני המופעים תלויים במשתנה זה‪ ,‬אבל אחד הפריע‬
‫לשני באמצע (ראו את הערך ‪ 0‬פעמיים בפלט)‬
‫‪ Java | thread‬מתקדם | ‪43 ©Keren Kalif‬‬
‫דוגמא ל‪deadlock -‬‬
‫‪‬‬
‫דוגמאת הפילוסופים הסינים‪:‬‬
‫‪o‬‬
‫‪ 5‬פילוסופים סינים יושבים מסביב לשולחן האוכל‪ .‬מול כל אחד יש צלחת‪ ,‬ובין כל ‪ 2‬צלחות‬
‫יש ‪.chopstick‬‬
‫‪o‬‬
‫כדי לאכול כל פילוסוף צריך ‪ ,chopstick 2‬והוא יכול לקחת רק את זה שמונח מימין או‬
‫משמאל לצלחת שלו‪.‬‬
‫‪o‬‬
‫אם כל פילוסוף יקח את המקל שלימינו‪ ,‬ולא יניח אותו עד שיסיים לאכול‪ ,‬לעולם אף פילוסוף‬
‫לא יוכל לאכול‪ ,‬וזהו למעשה ‪deadlock‬‬
‫התמונה לקוחה מ‪:‬‬
‫_‪http://en.wikipedia.org/wiki/Dining_philosophers‬‬
‫‪problem‬‬
44 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫מימוש‬
‫‪ Java | thread‬מתקדם | ‪45 ©Keren Kalif‬‬
‫השיטה ‪tryToEat‬‬
‫מחכה למזלג ואז נועל אותו‬
‫שחרור הנעילות על המזלגות‬
‫בסיום הבלוקים‬
‫‪ Java | thread‬מתקדם | ‪46 ©Keren Kalif‬‬
‫ה‪main -‬‬
‫הפתרון‪ :‬לנעול מזלג רק אם ‪ 2‬המזלגות‬
‫פנויים‪ .‬אפשר להשתמש לצורך כך באובייקט‬
‫‪ Semaphore‬המאפשר לבדוק נעילה‪.‬‬
‫לכל הפילוסופים יש את המזלג השמאלי‪ ,‬וכולם מחכים לימני‪..‬‬
‫יחכו לנצח כי אף אחד לא משחרר‪...‬‬
47 ©Keren Kalif | ‫ מתקדם‬Java | thread
Semaphore ‫עבודה עם‬
‫‪ Java | thread‬מתקדם | ‪48 ©Keren Kalif‬‬
‫השיטה ‪ tryToEat‬במימוש סמפור‬
‫מחכה עד שניתן לקבל נעילה על האובייקט‬
‫בודקת האם ניתן לקבל נעילה‬
‫אם לא ניתן לקבל נעילה גם על המזלג הימני‪,‬‬
‫משחררת את השמאלי‪ ,‬ויוצאת מהשיטה‪.‬‬
‫‪ run‬תנסה להפעיל שיטה זו שוב בהמשך‪.‬‬
‫‪ Java | thread‬מתקדם | ‪49 ©Keren Kalif‬‬
‫ה‪main -‬‬
‫כמה אובייקטים יכולים לבצע‬
‫את הנעילה בו"ז‪ ,‬והאם סדר‬
‫הפעולה שלהם הוא ‪FIFO‬‬
50 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫צרכן‬-‫בעיית היצרן‬
51 ©Keren Kalif | ‫ מתקדם‬Java | thread
52 ©Keren Kalif | ‫ מתקדם‬Java | thread
wait + notify ‫ באמצעות‬CubyHole ‫מימוש‬
‫‪ Java | thread‬מתקדם | ‪53 ©Keren Kalif‬‬
‫ממתין עד אשר יהיה מקום בקופסה‬
‫מודיע שיש עוגיות בקופסה‬
‫‪ Java | thread‬מתקדם | ‪54 ©Keren Kalif‬‬
‫ממתין שיהיו עוגיות בקופסה‬
‫מודיע שיש מקום בקופסה‬
‫‪ Java | thread‬מתקדם | ‪55 ©Keren Kalif‬‬
‫מנגנון סינכרון ע"י ‪Lock + Condition‬‬
‫‪‬‬
‫‪ Monitor‬הוא מנגנון המסנכרן בין לפחות שני ‪'thread‬ים‪ ,‬ומשתמש באובייקטים‬
‫‪ Lock‬ו‪ Condition -‬הקיימים בשפה‬
56 ©Keren Kalif | ‫ מתקדם‬Java | thread
Lock ‫הממשק‬
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
57 ©Keren Kalif | ‫ מתקדם‬Java | thread
Condition ‫הממשק‬
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html
58 ©Keren Kalif | ‫ מתקדם‬Java | thread
Lock + Condition ‫ באמצעות‬CubyHole ‫מימוש‬
59 ©Keren Kalif | ‫ מתקדם‬Java | thread
Producer / Consumer -‫ ולא בתוך ה‬CubyHole -‫הנעילה נמצאת בתוך ה‬
?‫מדוע‬
60 ©Keren Kalif | ‫ מתקדם‬Java | thread
61 ©Keren Kalif | ‫ מתקדם‬Java | thread
BlockingQueue ‫הממשק‬
‫הצלחת‬-‫לממשק זה יש מתודות המטפלות באופן שונה במקרה של אי‬
‫הכנסה מיידית‬/‫הסרה‬
)Blocking( ‫ חסימה‬true/false ‫החזרת‬
timeout

‫זריקת חריגה‬
offer(obj, timeout, unit)
put(obj)
offer(obj)
add(obj)
‫הוספה‬
poll(timeout, unit)
take(obj)
poll(obj)
remove(obj)
‫הסרה‬
ArrayBlockingQueue ‫לממשק זה מספר מימושים ובינהם‬

62 ©Keren Kalif | ‫ מתקדם‬Java | thread
BlockingQueue ‫ באמצעות‬CubyHole ‫מימוש‬
63 ©Keren Kalif | ‫ מתקדם‬Java | thread
BlockingQueue ‫ באמצעות‬CubyHole ‫מימוש‬
64 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫דוגמת פלט‬
‫‪ Java | thread‬מתקדם | ‪65 ©Keren Kalif‬‬
‫‪Synchronized Collections‬‬
‫‪‬‬
‫האוספים ב‪ java.util -‬מגרסה ‪( 1.5‬אלו המשתמשים ב‪ )generics -‬אינם‬
‫‪ ,ThreadSafe‬משמע ניתן להסיר ולהוסיף איברים בו"ז‪ ,‬מה שכמובן עלול לגרום‬
‫במקרים מסויימים לבעיות‬
‫‪o‬‬
‫האוספים הישנים (שהוגדרו ב‪ JDK1 -‬הם כן ‪ ThreadSafe‬אך כמעט ואינם בשימוש)‬
‫‪‬‬
‫ניתן להגדיר ‪ Synchronized Collection‬ע"י יצירת אוסף חדש שעוטף את‬
‫האוסף המקורי‪ ,‬ושם ב‪ synchronized -‬את המתודות ‪ add‬ו‪remove -‬‬
‫‪‬‬
‫אוספים אלו אינם מוגדרים כטיפוסים חדשים‪ ,‬אלא נוצרים ע"י שיטות עזר‬
‫‪ Java | thread‬מתקדם | ‪66 ©Keren Kalif‬‬
‫דוגמה‬
‫זוהי הפנייה לאותה רשימה‬
‫עבודה עם איטרטור צריכה להיות‬
‫בתוך בלוק ‪synchronized‬‬
‫‪ Java | thread‬מתקדם | ‪67 ©Keren Kalif‬‬
‫הגבלת מספר ה‪'thread -‬ים‬
‫‪‬‬
‫במקרה בו נרצה להגביל את כמות ה‪'thread -‬ים הרצים במקביל נשתמש ב‪-‬‬
‫‪ExecuterService‬‬
‫‪‬‬
‫דוגמא‪:‬‬
‫‪o‬‬
‫תור במרכז שירות ‪ /‬קופאיות בסופר‪ :‬בכל רגע נתון מטפלים רק ב‪ X -‬לקוחות ובשלב מסויים‬
‫רוצים לסגור את התור לקבלת קהל נוסף‬
68 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫ הלקוח‬:‫דוגמא‬
‫‪ Java | thread‬מתקדם | ‪69 ©Keren Kalif‬‬
‫דוגמא‪ :‬ה‪main -‬‬
‫לחכות עד שכל ה‪'thread -‬ים‬
‫יסיימו או ‪ 10‬שניות‪ ,‬מה שבא קודם‪.‬‬
‫ניתן לראות שאחרי ש‪ 6 -‬לקוחות נכנסים החנות‬
‫לא מקבלת יותר לקוחות‪.‬‬
‫וכן אחרי סיום טיפול בלקוח מתחיל טיפול באחר‪.‬‬
‫‪ Java | thread‬מתקדם | ‪70 ©Keren Kalif‬‬
‫המחלקה ‪Executors‬‬
‫‪‬‬
‫יש לה מתודות סטטיות ליצירת סוג ה‪ ExecutorService -‬מהסוג המבוקש‪,‬‬
‫ובינהן‪:‬‬
‫‪o‬‬
‫‪ newFixedThreadPool‬המגדיר כמה ‪'thread‬ים יוכלו לעבוד בו‪-‬זמנית‬
‫‪o‬‬
‫‪ newCachedThreadPool‬המאפשר שימוש בלתי מוגבל של ‪'thread‬ים‪ ,‬אבל יודע‬
‫להשתמש בזכרון של ‪'thread‬ים שכבר סיימו עבודתם (במקום יצירת אובייקט חדש עבור כל‬
‫‪)thread‬‬
‫‪ Java | thread‬מתקדם | ‪71 ©Keren Kalif‬‬
‫הממשק ‪ :Callable‬קבלת ערך מ‪ thread -‬לאחר שסיים את ריצתו‬
‫‪‬‬
‫עד כה ה‪'thread -‬ים הסתיימו ולא ביקשנו מהם ערך מוחזר‬
‫‪‬‬
‫כדי לקבל את הערך המוחזר של ‪ thread‬מסויים‪ ,‬יש לחכות שקודם כל ה‪-‬‬
‫‪'thread‬ים יסיימו את ריצתם‪ ,‬כי אחרת לא נדע האם ה‪ thread -‬כבר סיים את‬
‫פעולתו וניתן לקבל את הערך שחישב‬
‫‪‬‬
‫ניתן להשתמש בממשק ‪ ,Callable‬במקום בממשק ‪ ,Runnable‬אשר בו‬
‫המתודה להרצה (‪ )call‬מחזירה ערך‪ ,‬בניגוד למתודה ‪ run‬שמחזירה ‪void‬‬
‫‪‬‬
‫בנוסף‪ ,‬המתודה ‪ call‬יכולה לזרוק חריגה‪ ,‬בעוד שהחתימה של ‪ run‬אינה‬
‫מאפשרת זאת‬
‫‪‬‬
‫הממשק ‪ Callable‬הצטרף לפשה רק החלק מגרסה ‪ 1.5‬ומטעמי תאימות לאחור‬
‫הממשק ‪ Runnable‬נותר קיים‬
72 ©Keren Kalif | ‫ מתקדם‬Java | thread
-‫דוגמא לשימוש ב‬
Runnable
‫‪ Java | thread‬מתקדם | ‪73 ©Keren Kalif‬‬
‫דוגמה לשימוש ב‪Callable -‬‬
‫‪‬‬
‫ניתן לקבל את ערכו של ‪ thread‬גם בלי לחכות לסיום כל שאר ה‪'thread -‬ים‬
‫יש לממש את הממשק‪ ,‬ולהגדיר מהו‬
‫טיפוס הערך המוחזר בסיום ההרצה‬
‫טיפוס הערך המוחזר כפי שהוגדר‬
‫בשורת מימוש הממשק‬
‫השיטה רצה ב‪ thread -‬נפרד‬
‫ומחזירה ערך לאחר סיומה‬
‫‪ Java | thread‬מתקדם | ‪74 ©Keren Kalif‬‬
‫הרצת משתנה ‪ Callable‬אינה באמצעות ‪ thread‬אלא‬
‫באמצעות השיטה ‪ submit‬של ‪ExecuterService‬‬
‫איחסון כל ההרצות שעבורן מחכים לתשובה‬
‫מסיים את פעולת ה‪,ServiceExecuter -‬‬
‫אחרת ה‪ main -‬אינו מסתיים‬
‫מחכה שתתקבל התשובה‪ .‬כלומר התשובות‬
‫יהיו לפי סדר יצירת האובייקטים‪.‬‬
‫‪ Java | thread‬מתקדם | ‪75 ©Keren Kalif‬‬
‫ניתן לראות שסדר התשובות‬
‫הוא לפי סדר יצירת האובייקטים‬
‫‪ Java | thread‬מתקדם | ‪76 ©Keren Kalif‬‬
‫בעיית ה‪Lost-Wakeup Problem -‬‬
‫‪‬‬
‫היפהייפיה הנרדמת ישנה עד אשר הנסיך שולח לה נשיקה‪ .‬אם הוא שלח נשיקה‬
‫לפני שהיא נרדמה‪ ,‬היא לעולם לא תתעורר!‬
‫‪‬‬
‫כלומר‪ ,‬כאשר נשלח ‪ notify‬לפני שהופעל ה‪..wait -‬‬
77 ©Keren Kalif | ‫ מתקדם‬Java | thread
78 ©Keren Kalif | ‫ מתקדם‬Java | thread
79 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫‪ Java | thread‬מתקדם | ‪80 ©Keren Kalif‬‬
‫‪CountDownLatch‬‬
‫‪‬‬
‫אובייקט המאפשר ל‪ thread -‬להמתין עד אשר ‪'thread‬ים אחרים יתחילו‪/‬יסיימו‬
‫את עבודתם‬
‫‪‬‬
‫משמש לצורכי סינכרון‬
‫‪o‬‬
‫למשל‪ ,‬שהנסיך לא ישלח נשיקה לפני שהיפהיפיה הנרדמת הלכה לישון‬
‫‪ Java | thread‬מתקדם | ‪81 ©Keren Kalif‬‬
‫‪ – FairyTale‬גרסה מתוקנת‬
‫מסמן שהפעולה בוצעה‬
82 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫ על האובייקט‬countDown ‫מחכה שתופעל‬
83 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫‪ Java | thread‬מתקדם | ‪84 ©Keren Kalif‬‬
‫שימושים לסנכרון זה‬
‫‪‬‬
‫ניתן להשתמש באובייקט זה כאשר יש שני ‪'thread‬ים שמאותחלים ביחד‪ ,‬אך‬
‫רוצים לדאוג שה‪ start -‬של אחד יחל רק לאחר שהשני סיים‬
‫‪‬‬
‫דוגמא‪:‬‬
‫‪o‬‬
‫בהינתן ‪ thread‬המייצג מכונית ו‪ thread -‬המייצג שער‪ ,‬נרצה לדאוג שה‪ thread -‬של‬
‫השער יתחיל פעולתו לפני המכונית‬
‫‪o‬‬
‫לוגית‪ ,‬הגיוני שקודם יש שערים‪ ,‬ואח"כ מכוניות‬
‫‪o‬‬
‫אפילו אם קוראים ל‪ start -‬ל‪ thread -‬של השער לפני ה‪ start -‬של ה‪ thread -‬של‬
‫המכונית‪ ,‬איך הכרח שהשער ירוץ קודם‬
‫‪o‬‬
‫באמצעות ‪ CountDownLatch‬ניתן לדאוג לכך‬
‫‪ Java | thread‬מתקדם | ‪85 ©Keren Kalif‬‬
‫תרגיל‬
‫‪‬‬
‫‪‬‬
‫יש לדמות סיטואציה של ישיבה‪:‬‬
‫‪o‬‬
‫יש להמתין ל‪ chairman -‬שיפתח את הישיבה‬
‫‪o‬‬
‫יש להמתין ל‪ 3 -‬דירקטורים שיגיעו לישיבה‬
‫‪o‬‬
‫לא ניתן להתחיל את הישיבה עד אשר הודלק המקרן‬
‫‪ Main‬לדוגמה והפלט בשקפים הבאים‬
86 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫ לדוגמה‬main -‫ה‬
‫ להורדה‬main -‫קובץ ה‬
87 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫פלט אפשרי לתוכנית‬
‫‪ Java | thread‬מתקדם | ‪88 ©Keren Kalif‬‬
‫‪CyclicBarrier‬‬
‫‪‬‬
‫אובייקט סינכרון דומה ל‪CountDownLatch -‬‬
‫‪‬‬
‫העבודה של האובייקט הינה מחזורית‪ ,‬לאחר שהתור התמלא וכל האובייקטים‬
‫שבו סיימו עבודתם‪ ,‬הוא ימתין לסיבוב נוסף‬
‫‪‬‬
‫‪o‬‬
‫‪ CyclicBarrier‬מאפשר ריצת ה‪ run -‬של ‪ thread‬יותר מפעם אחת‬
‫‪o‬‬
‫כמו ה‪ CountDownLatch -‬אבל עובד במחזוריות‬
‫למשל‪:‬‬
‫‪o‬‬
‫מונית שירות מתחילה את המסלול רק לאחר שיש מינימום נוסעים‪ ,‬ואחרי סיבוב אחד‬
‫מבצעת סיבוב נוסף‬
‫‪o‬‬
‫מתקן בלונה‪-‬פארק מתחיל לפעול רק לאחר שיש מינימום מבלים‪ ,‬ושוב ושוב‬
‫‪ Java | thread‬מתקדם | ‪89 ©Keren Kalif‬‬
‫‪ – CyclicBarrier‬דוגמא ‪ -‬המונית‬
‫נראה בהמשך שה‪ run -‬יופעל יותר‬
‫מפעם אחת לאובייקט ‪ Taxi‬יחיד‬
90 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫ הנוסע‬- ‫ – דוגמא‬CyclicBarrier
‫מחכה שכל המכסה תתמלא‬
‫‪ Java | thread‬מתקדם | ‪91 ©Keren Kalif‬‬
‫‪main –CyclicBarrier‬‬
‫ה‪ thread -‬שירוץ‬
‫מספר האובייקטים שצריכים‬
‫להצטבר עבור התחלת הפעולה‬
‫אם הלולאה תרוץ ‪ 7‬פעמים‪ ,‬התוכנית לא תסתיים‪,‬‬
‫מאחר ויהיה ניסיון למלא את המונית עבור לקוח זה‪..‬‬
‫‪ Java | thread‬מתקדם | ‪92 ©Keren Kalif‬‬
‫‪ - CyclicBarrier‬הפלט‬
‫– פלט‬
‫ניתן לראות שה‪ run -‬של ‪Taxi‬‬
‫בסיבוב השני התחיל רק לאחר‬
‫סיום ה‪ run -‬של הסיבוב הראשון‬
‫‪ Java | thread‬מתקדם | ‪93 ©Keren Kalif‬‬
‫מימושים של מנעולים‬
‫‪‬‬
‫‪ :ReentrantLock‬מאפשר לאובייקט שמחזיק במנעול להחזיקו שוב‬
‫‪o‬‬
‫המטרה היא למנוע מצב בו לאובייקט יש ‪ deadlock‬עם עצמו‬
94 ©Keren Kalif | ‫ מתקדם‬Java | thread
ReentrantLock ‫מימוש של‬
‫‪ Java | thread‬מתקדם | ‪95 ©Keren Kalif‬‬
‫אם האובייקט הזה הוא הנועל‪ ,‬נגדיל את מספר הנעילות‬
‫אם ישנה נעילה‪ ,‬ולא ע"י אובייקט זה‪ ,‬יש להמתין‬
‫‪ Java | thread‬מתקדם | ‪96 ©Keren Kalif‬‬
‫אם המנעול אינו מוחזק ע"י‬
‫אף אחד‪ ,‬אין צורך לבצע דבר‪..‬‬
‫אם זו הנעילה האחרונה‪ ,‬יש‬
‫לסמן שהנעילה הסתיימה‬
97 ©Keren Kalif | ‫ מתקדם‬Java | thread
ReadWriteLock ‫מימוש‬
:‫מחלקות המממשות ממשק זה‬
)‫מאפשרות קוראים מרובים (שאינם משנים את המידע‬
o
‫מאפשרות כותב יחיד‬
o
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html

98 ©Keren Kalif | ‫ מתקדם‬Java | thread
ReadWriteLock ‫מימוש‬
99 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫‪ Java | thread‬מתקדם | ‪100 ©Keren Kalif‬‬
‫נשים לב‪ :‬במימוש זה‪ ,‬בזמן שהכותב‬
‫מחכה‪ ,‬יתכן ויכנסו קוראים נוספים‪ ,‬ולכן‬
‫הכותב לעולם לא יקבל את הנעילה‬
‫‪ Java | thread‬מתקדם | ‪101 ©Keren Kalif‬‬
‫נעילה הוגנת‪Fair Readers-Writers :‬‬
‫‪‬‬
‫במקרה בו יש קוראים רבים‪ ,‬ישנו סיכוי שהכותב לעולם לא יכנס לקטע הקריטי‬
‫‪‬‬
‫לכן ישנו מימוש שברגע שהכותב מבקש נעילה‪ ,‬אין אפשרות כניסה לקוראים‬
‫נוספים לקטע הקריטי‬
102 ©Keren Kalif | ‫ מתקדם‬Java | thread
Fair Readers-Writers Lock implementation
103 ©Keren Kalif | ‫ מתקדם‬Java | thread
104 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫‪ Java | thread‬מתקדם | ‪105 ©Keren Kalif‬‬
‫מימוש ‪( Semaphore‬הומצא ע"י דיקסטרה!)‬
‫‪‬‬
‫למחלקת ‪ Semaphore‬ישנן ‪ 3‬מתודות מרכזיות‪acquire, release, tryAcuire :‬‬
‫‪‬‬
‫יתרונו שהוא שמאפשר נעילה זו‪-‬זמנית ע"י כמה אובייקטים‬
‫‪‬‬
‫המתודה ‪ acquire‬היא ‪ blocking‬בעוד המתודה ‪ tryAcquire‬היא סינכרונית‬
106 ©Keren Kalif | ‫ מתקדם‬Java | thread
Semaphore implementation
‫‪ Java | thread‬מתקדם | ‪107 ©Keren Kalif‬‬
‫השוואה בין שימוש ב‪ Lock -‬לעומת ‪wait+notify‬‬
‫‪‬‬
‫אובייקט ‪ Lock‬מחליף את בלוק ה‪ synchronized -‬והאובייקט‬
‫‪ Condition‬מחליף את שיטות אובייקט המוניטור (‪)wait+notify‬‬
‫‪‬‬
‫כאשר משתמשים ב‪ Lock -‬ניתן לבחור באיזה מימוש שלו להשתמש‪:‬‬
‫‪ Reentrant, ReaderWriter, Fifo‬וכד'‬
‫‪‬‬
‫יש הטוענים שהקוד קריא יותר כאשר משתמשים ב‪..Lock -‬‬
‫‪ Java | thread‬מתקדם | ‪108 ©Keren Kalif‬‬
‫‪ – EDT‬ה‪ thread -‬להפעלת ה‪GUI -‬‬
‫‪‬‬
‫את ה‪ swing -‬גם נריץ ב‪ thread -‬נפרד כדי שנוכל להריץ את הלוגיקה שלנו‬
‫במקביל בלי תקיעויות‪ .‬כלומר‪ ,‬שאם קורה אירוע בזמן ציור ה‪ ,GUI -‬התוכנית לא‬
‫"תתקע"‬
‫‪‬‬
‫‪ Thread‬זה נקרא ‪)EDT( Event Dispatch Thread‬‬
‫‪‬‬
‫ה‪ Swing -‬עצמו מריץ את רוב המתודות שלו ב‪ EDT -‬מאחר והקוד של ‪Swing‬‬
‫אינו ‪( Thread-Safe‬משמע תיתכן פניה ועדכון בו"ז של משתנה מסויים)‪ ,‬וה‪-‬‬
‫‪ EDT‬דואג לסנכרון הפעולות‬
‫‪‬‬
‫באפליקציות גדולות‪'thread ,‬ים אחרים ירצו לעדכן את ה‪ ,GUI -‬וכדי למנוע‬
‫"תקיעות" וכדי שהעבודה תיעשה במקביל‪ ,‬כל ניסיון פניה ל‪ GUI -‬יהיה דרך ה‪-‬‬
‫‪EDT‬‬
109 ©Keren Kalif | ‫ מתקדם‬Java | thread
‫ הקוד‬- ‫ נפרד‬thread -‫ ב‬swing -‫הפעלת ה‬
110 ©Keren Kalif | ‫ מתקדם‬Java | thread
:‫ביחידה זו למדנו‬
‫ ותכונותיו‬Thread
Runnable ‫הממשק‬
‫'ים‬thread ‫מצבים של‬
deadlock -‫ ו‬racing :‫סינכרון תהליכים‬
‫סמפורים‬
Condition+Lock ‫מוניטור ע"י‬
ArrayBlockingQueue
ExecuterService ‫'ים ע"י‬thread -‫הגבלת מספר ה‬
Callable ‫ ע"י הממשק‬thread -‫קבלת ערך מ‬
CountDownLatch -‫ ו‬CyclicBarrier :‫'ים‬thread ‫המתנה לכמות מסויימת של‬
‫אובייקט אנונימי‬
‫אלגוריתמי נעילה‬











