הרצאה מספר#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 2025