הרצאה מספר#09 : Threads תכנות ג'אווה +אינטרנט JAVA & WEB PROGRAMMING צבי מלמד מכללת הדסה/מכללה חרדית © כל הזכויות שמורות 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 1 הערה • • • • מצגת זאת נכתבה עבור תלמידים שיודעים כבר היטב נושא של פתילים threadsבהיבט של מערכות הפעלה בכלל ,ותכנות מערכת כולל פתילים בלינוקס בפרט ,ובכלל זה נושאים של סנכרון בין תהליכים ,שימוש בסמפורים ,וכו' המצגת מבוססת על פרק 26בספר של – Deitel & Deitel: Java How to program 9th Ed. דוגמאות ההרצה אף הן מבוססות על הספר הזה. מודגשים ההיבטים "הג'אווה-אים" של הנושא ,כלומר הכלים ש- JAVAמספקת לנו בכדי לטפל בפתילים. 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 2 מבוא • שפת ג'אווה מספקת מקביליות באמצעות השפה ובאמצעות ה API שלה • המקביליות מושגת על ידי שימוש בפתילים – תהליכונים – threads • במחשבים מרובי מעבדים – הפתילים עשויים לרוץ על מעבדים שונים 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 3 Thread Statesמצבי הפתיל • .1 .2 .3 .4 .5 .6 בכל רגע נתון ,כל פתיל יכול להיות באחד מהמצבים המתוארים בתרשים הבא. פתיל מתחיל את חייו במצב .newבמצב זה עד שהוא "מתחיל" לאחר שהתחיל/אותחל מוצב במצב runnable עובר למצב waitingכאשר מחכה לפתיל אחר לבצע משימה כלשהי ממצב runnableהוא יכול לעבור גם למצב time-waitingלמשך אינטרוול קצוב של זמן .יוצא ממצב זה או כאשר נגמר הזמן או שקרה אירוע שהפתיל המתין לו פקודת )( – sleepמעבירה למצב .time-waitingיוצא משם כעבור פרק הזמן למצב runnable סיום המשימה של הפתיל (בעצמו או כהוראה ממישהו חיצוני לפתיל) מעביר אותו למצב terminated 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 4 Thread Statesמצבי הפתיל 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 5 עוד על Thread Statesמצבי הפתיל • מבחינת JAVAהפתיל במצב runnable • מבחינת מערכת ההפעלה הוא יכול להיות runningאו ready • העברתו למצב runningנקראת dispatching the threadומתבצעת על ידי המודול במערכת ההפעלה שאחראי לזה ,בד"כ thread- schedulerאו dispatcherשמעניק לפתיל quantumשל זמן או time-slice 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 6 עוד מבוא על פתילים בJAVA - • • • • • לכל פתיל ב JAVAיש thread priorityשמשפיע על קדימותו לקבל זמן מעבד אין בכך הבטחה או התחייבות באיזה סדר יזומנו הפתילים מושגים שלמדנו במערכות הפעלה ,כגוןpreemptive scheduling, : starvation, aging (i.e. raising priority with age to prevent ) – starvationכל אלו ,תקפים ומתקיימים. ההתנהגות של אפליקציות מרובות פתילים תהיינה שונה בין מערכות ההפעלה ,כתלות במימוש הפתילים במערכות השונות מומלץ לא לייצר פתילים ) (thread objectsבמישרין ,אלא להשתמש בממשק Executor 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 7 Creating and Executing Threads with Executor Framework • - A Runnable objectמשימה שיכולה להתבצע ,לרוץ ,במקביל למשימות אחרות • Runnable interfaceמגדיר מתודה בודדת run :שמכילה את הקוד שהפתיל צריך לבצע .זאת בעצם פונקציית הכניסה של הפתיל. • בכדי לבצע threadמייצרים את האובייקט המתאים (כאמור ,זהו אובייקט שמממש את הממשק )runnableוקוראים למתודה run שמתבצעת בתוך תהליכון (פתיל) שונה ,חדש. 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 8 Creating and Executing Threads with - Executor Frameworkדוגמא 26.3 • • • • • בדוגמא זאתClass PrintTask implements Runnable : מתודה סטטית )( sleepשל המחלקה Thread המתודה יכולה לזרוק חריג InterruptedExceptionולכן הקריאה לה נמצאת בתוך try-catchמתאים התוכנית מסתיימת כאשר הפתיל האחרון מסיים להתבצע ה Executor -מנהל מאגר פתילים thread poolועי"כ יכול להשתמש מחדש reuseבפתילים ולשפר מהירות מעביר את האובייקט (שהוא ( )runnableארגומנט של המתודה )executeלאחד הפתילים במאגר .אם אין פתיל פנוי – יוצר חדש או ממתין שאחד שרץ יסתיים 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 9 Creating and Executing Threads with - Executor Frameworkדוגמא 26.3 • הממשק ExecutorServiceיורש מ Executor -ומגדיר מתודות לניהול-שליטה במחזור החיים של הExecutor - • יצירה על ידי קריאה למתודה הסטטית של המחלקה Executors בשם newCachedThreadPoolשמחזירה ExecutorServiceשיוצרת פתילים חדשים שדרושים לאפליקציה • המתודה shutdownמודיעה ל ExecutorService -להפסיק לקבל משימות חדשות ,אבל להמשיך לבצע את אלו שכבר נשלחו 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 15 סנכרון פתילים • כאמור בהערת המבוא -הרקע לנושא זה לא מכוסה כאן... • המטרה לאפשר גישה אקסקלוסיבית לקוד שמטפל באובייקט משותף ,כלומר להשיג mutual exclusion • המטרה מושגת באמצעות monitors – לכל אובייקט יש monitorו monitor lock -שיכולים להיות מוחזקים רק בידי פתיל אחד בכל רגע נתון. – הפתיל צריך לקבל-להשיג acquireאת המנעול לפני שהוא ממשיך בפעולתו .אם המוניטור לא פנוי ,הוא נחסם blocked 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 16 סנכרון פתילים • כיצד משיגים את האפקט הזה? – על ידי שמקדימה לפקודה (פקודות) את המילה synchronized ) – synchronized ( object { statements } // end synchronized statement – כאשר objectהוא האובייקט שלגביו רוצים להפעיל את הmonitor - ,lockבדרך כלל זה יהיה האובייקט this – אבל אם נרצה באובייקט/מחלקה Aלדאוג שקטע קוד יסונכרן עבור אובייקט אחר ,B1אזי נוכל בתוך המחלקה Aלכתוב – לחליפין ,אפשר להגדיר מתודה שלמה כ synchronized • הערה :הנעילה איננה על קטע קוד מסוים ,אלא על כל קטעי הקוד של אותו אובייקט. – כלומר :אם נעלנו קטע קוד מסוים של אובייקט ,Xאזי בו זמנית לא ניתן לבצע מתודה אחרת של אותו אובייקט (או קטע קוד אחר) שמסומן ב synchronized 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 17 סנכרון פתילים -הבהרות • • אם נרצה באובייקט של מחלקה Aלדאוג שקטע קוד יסונכרן עבור אובייקט אחר b1של מחלקה ,Bאזי נוכל בתוך המחלקה Aלכתוב: ;)(B b1 = new B )synchronized ( b1 { specific statements to synchronize } // end synchronized statement קטע הקוד הזה יצטרף לכלל הקטעים שהם בסנכרון עבור האובייקט ,b1כלומר אם הגדרנו במחלקה Bמספר מתודות שהן synchronizedברמת המתודה ,אזי כל המתודות האלו ,וגם הקטע הספציפי הזה ,כולם נכנסים למנגנון הנעילה.. כלומר בו-זמנית הם מתבצעים לכל היותר על ידי יותר פתיל אחד. 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 18 מממשת אתArrayWriter (Fig. 26.6) המחלקה interface Runnable to define a task for הממשק inserting values in a SimpleArray object. The task completes after three consecutive integers beginning with startValue are added to the SimpleArray object. דרוש עיבוד © Copyright 1992-2012 by Pearson Education, Inc. All Rights Reserved. Class SharedArrayTest (Fig. 26.7) executes two ArrayWriter tasks that add values to a single SimpleArray object. ExecutorService’s shutDown method prevents additional tasks from starting and to enable the application to terminate when the currently executing tasks complete execution. We’d like to output the SimpleArray object to show you the results after the threads complete their tasks. ◦ So, we need the program to wait for the threads to complete before main outputs the SimpleArray object’s contents. ◦ Interface ExecutorService provides the awaitTermination method for this purpose—returns control to its caller either when all tasks executing in the ExecutorService complete or when the specified timeout elapses. © Copyright 1992-2012 by Pearson Education, Inc. All Rights Reserved. יצירת פעולות אטומיות • • • • • • • הפלט בדוגמא הקודמת הוא "מבולבל" או לא נכון ...בגלל שהפתילים אינם thread safe "דורכים ומקלקלים" את הערך של המשתנה writeIndex צריך שפעולה העדכון והכתיבה של המערך ושל האינדקס שלו ,יהיו פעולות אטומיות כאמור לעיל ,האטומיות ניתנת להשגה על ידי שימוש במילת המפתח synchronized הדוגמא 26.8ממחישה שימוש במחלקה simpleArrayבדוגמא הקודמת ,אלא שכאן דואגים לסינכרון. שימו לב שלצורך הדוגמא הדפסות פלט נמצאות בתוך .synchronizedזה טוב להדגמות ורע מאוד לתכנה אמתית. (מדוע??) 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 28 יצירת פעולות אטומיות • כללים בהקשר זה: – קטעי הקוד שהם בתוך synchronizedצריכים להיות קצרים ומהירים בכדי לעקב במידה מינימלית פתילים שממתינים למנעול – מנעול דרוש רק עבור shared mutable data – אם המידע המשותף בין הפתילים איננו mutableלא דרוש מנעול ...אבל.. – אבל מומלץ להשתמש ב final -בכדי לחדד את העובדה שלא דרוש מנעול 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 33 דוגמא – producer-consumer • היצרן והצרכן כותבים לתוך Bufferחוצץ • כדאי – מומלץ – להשתמש בממשק – interfaceלהלן: 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 34 היצרן – המחלקה Producer הקונסטרקטור מקבל ארגומנט: את ה buffer -שלתוכו יכתוב היצרן – המחלקה Producer ישן זמן אקראי ואז כותב לתוך ה sharedLocation -את המספר count 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 36 הצרכן– המחלקה Consumer הקונסטרקטור מקבל ארגומנט: את ה buffer -שממנו יקרא UnsynchronizedBuffer המחלקה SharedBufferTest המחלקה סינכרון באמצעות ArrayBlockingQueue- • • • • ל JAVA-יש – concurrency packageמארז מחלקות/פתרונות לבעיות מקביליות java.util.concurrent המחלקה ArrayBlockingQueueהיא thread-safe שמממשת את הממשק BlockingQueue מספקת מתודות putוtake - – Putשמה אלמנט בסוף התור .ממתינה אם התור מלא – Takeלוקחת/מורידה אלמנט .ממתינה אם התור ריק 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 47 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 52 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 53 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 54 סנכרון בעצמנו... • • • • על ידי שימוש ב synchronized -ובמתודות של Object כותבים get, setתוך שימוש ב synchronized המתודות של – wait, notify, notifyAll :Objectמשמשות לסינכרון ההמתנה – )( Waitעל אובייקט עם מסונכרן – משחרר את המנעול ,ומעביר את הקורא למצב waiting state – )( – notifyמעביר תהליך אחד מהממתינים למצב runnable – )( – notifyAllמעביר את כל התהליכים שממתינים למצב – runnableכלומר הם יכולים לבקש את המנעול שגיאה :אסור לקרוא למתודות הנ"ל מבלי שקודם כל דאגנו לקבל את המנעול! זה יגרום לחריגה IllegalMonitorStateException 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 55 סנכרון – חוצץ ציקלי • • • • • הבעיה בדוגמא הקודמת – אם הייצרן והצרכן אינם עובדים באותו קצב – הם מאיטים אחד את השני (בכל פעם אחד מהם מחכה לשני) פתרון אפשרי (שהכרנו בעבר) – חוצץ שמכיל מספר תאים לשמירת המוצרים שהיצרן ייצר ניתן להשתמש ב ArrayBlockingQueue -והמחלקה דואגת לכל פרטי הסנכרון אפשר לממש בעצמנו חוצץ ציקלי – - CircularBufferראו דוגמא 26.18-19 הדוגמא איננה מובאת בשקפים אלו. 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 65 The Lock and Condition Interfaces • • • • • • לכל האובייקטים שרוצים להסתנכרן על מנעול מסוים ,יש reference לאובייקט שמממש את הממשק Lock קריאה למתודות lock or unlock אם מספר פתילים מנסים לקרוא ל lock -בו זמנית ,מובטח שרק אחד מהם יצליח והאחרים יכנסו למצב waiting stateעבור המנעול הזה קריאה ל unlock -משחררת את המנעול ,ואחד הפתילים שנמצא בהמתנה מקבל אותו וממשיך לרוץ (עובר למצב ריצה) הממשק ממומש על ידי המחלקה ReentrantLock הקונסטרקטור מקבל ארגומנט בוליאני האם להפעיל fairness .policyאם trueאזי מופעלת המדיניות – "הפתיל שמחכה הכי הרבה זמן ,הוא זה שיקבל את המנעול ברגע שהמנעול יתפנה" – נחמד להיות הוגן ...אבל פוגע בביצועים לעומת העדר הוגנות 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 66 The Lock and Condition Interfaces • • • • • • • פתיל שתפש מנעול ,עשוי לגלות שהוא לא יכול להמשיך בפעולתו ,עד שמתקיים תנאי מסוים (למשל ,הצרכן ,עד שיש מוצרים לצרוך בחוצץ). ניתן להמתין על condition object זהו אובייקט שמממש את הממשק Condition Condition objectמשויכים למנעול מסוים ,ספציפי. יוצרים אותם על ידי קריאה למתודה newConditionשל המנעול הספציפי לאחר שיצרנו את האובייקט ,בכדי להמתין נקרא למתודה awaitשלו – מידית משחרר את המנעול – שם את הפתיל בתור הממתינים עבור ה condition -הזה פתיל אחר ,שרץ ,יבצע קריאה signalאו signalAllשל ה- conditionהזה ובהתאמה פתיל אחד מהממתינים ,או כולם יעברו למצב runnable 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 67 The Lock and Condition Interfaces – הערות • עלינו להבטיח שאיננו יוצרים deadlock • יש להציב קריאות ל unlock-בתוך בלוק !finallyעי"כ אם קורית חריגה ,הבלוק עדיין מתבצע והמנעול ישתחרר. • אם לא נעשה כן ...ותקרה חריגה אזי "המנעול ימות" • דוגמאFig_26_20-21 : 30דצמבר 12 © צבי מלמד – כל הזכויות שמורות 68
© Copyright 2024