IllegalMonitorStateException בג'אווה

1. סקירה כללית

במדריך קצר זה נלמד על java.lang.IllegalMonitorStateException.

ניצור יישום פשוט של שולח-מקלט שמקבל חריג זה. לאחר מכן נדון בדרכים אפשריות למנוע זאת. לסיום, נראה כיצד ליישם כיתות שולח ומקלט אלה בצורה נכונה.

2. מתי הוא מושלך?

ה IllegalMonitorStateException קשור לתכנות ריבוי הליכים ב- Java. אם יש לנו לפקח ברצוננו לסנכרן הלאה, חריג זה נזרק כדי להצביע על כך ששרשור ניסה להמתין או להודיע ​​על שרשורים אחרים הממתינים בצג זה, מבלי להיות בעלים עליו. במילים פשוטות יותר, נקבל חריג זה אם נקרא לאחד מה- לַחֲכוֹת(), לְהוֹדִיעַ(), אוֹ notifyAll () שיטות של לְהִתְנַגֵד כיתה מחוץ לא מסונכרן לַחסוֹם.

בואו עכשיו לבנות דוגמא שזורקת IllegalMonitorStateException. לשם כך נשתמש בשניהם לַחֲכוֹת() ו notifyAll () שיטות לסנכרון חילופי הנתונים בין שולח למקלט.

ראשית, בואו נסתכל על ה- נתונים כיתה המחזיקה את המסר שאנו נשלח:

מחלקה ציבורית נתונים {הודעת מחרוזת פרטית; שלח בטל ציבורי (הודעת מחרוזת) {this.message = הודעה; } מחרוזת ציבורית קבלת () {הודעה חוזרת; }}

שנית, בואו ניצור את מחלקת השולח שזורקת IllegalMonitorStateException כאשר מופעל. לשם כך, אנו קוראים notifyAll () שיטה מבלי לעטוף אותה ב- מסונכרן לַחסוֹם:

מחלקה UnsynchronizedSender מיישמת Runnable {יומן לוגר סופי סטטי פרטי = LoggerFactory.getLogger (UnsychronizedSender.class); נתוני נתונים סופיים פרטיים; שולח ציבורי לא מסונכרן (נתוני נתונים) {this.data = data; } @ עקוף הפעלה בטלנית ציבורית () {נסה {Thread.sleep (1000); data.send ("מבחן"); data.notifyAll (); } לתפוס (InterruptedException e) {log.error ("החוט הופרע", e); Thread.currentThread (). Interrupt (); }}}

המקלט הולך גם לזרוק IllegalMonitorStateException. בדומה לדוגמא הקודמת, אנו מתקשרים אל ה- לַחֲכוֹת() שיטה מחוץ ל מסונכרן לַחסוֹם:

מחלקה ציבורית UnsynchronizedReceiver מיישמת Runnable {private logic logger log log = LoggerFactory.getLogger (UnsynchronizedReceiver.class); נתוני נתונים סופיים פרטיים; הודעת מחרוזת פרטית; מקבל לא מסונכרן (נתוני נתונים) ציבורי {this.data = data; } @ ביטול הפעלה בטלנית ציבורית () {נסה {data.wait (); this.message = data.receive (); } לתפוס (InterruptedException e) {log.error ("החוט הופרע", e); Thread.currentThread (). Interrupt (); }} getMessage () מחרוזת פומבית (הודעה חוזרת; }}

לבסוף, בואו נפתח את שני השיעורים ונשלח הודעה ביניהם:

sendData בטל בציבור () {Data data = Data new (); מקלט מקלט לא מסונכרן = מקלט לא מסונכרן חדש (נתונים); Thread receiverThread = Thread חדש (מקלט, "חוט מקלט"); receiverThread.start (); שולח UnsynchronizedSender = חדש UnsynchronizedSender (נתונים); אשכול senderThread = שרשור חדש (שולח, "שולח השולח"); senderThread.start (); senderThread.join (1000); receiverThread.join (1000); }

כשאנחנו מנסים להריץ את פיסת הקוד הזו, נקבל IllegalMonitorStateException משניהם לא מסונכרן ו שולח לא מסונכרן שיעורים:

[thread-thread] ERROR com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender - חריגת מצב צג לא חוקי התרחשה java.lang.IllegalMonitorStateException: null ב- java.base / java.lang.Object.notifyAll (שיטה מקורית) ב- com.baeldung.exceptions .illegalmonitorstate.UnsynchronizedSender.run (UnsynchronizedSender.java:15) ב- java.base / java.lang.Thread.run (Thread.java:844) [thread-thread] ERROR com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedReceiver - צג לא חוקי חריג המדינה התרחש java.lang.IllegalMonitorStateException: null ב- java.base / java.lang.Object.wait (שיטה מקורית) ב- java.base / java.lang.Object.wait (Object.java:328) ב- com.baeldung. exceptions.illegalmonitorstate.UnsynchronizedReceiver.run (UnsynchronizedReceiver.java:12) at java.base / java.lang.Thread.run (Thread.java:844) 

3. כיצד לתקן את זה

להיפטר מה- IllegalMonitorStateException, אנחנו צריכים לבצע כל שיחה לַחֲכוֹת(), לְהוֹדִיעַ(), ו notifyAll () שיטות בתוך מסונכרן לַחסוֹם. עם זאת בחשבון, בואו נראה כיצד היישום הנכון של ה- שׁוֹלֵחַ הכיתה צריכה להיראות כך:

מחלקה SynchronizedSender מיישמת Runnable {פרטי נתונים סופיים פרטיים; SynchronizedSender ציבורי (נתוני נתונים) {this.data = נתונים; } @ עקוף ריצת חלל ציבורית () {מסונכרן (נתונים) {data.send ("מבחן"); data.notifyAll (); }}}

שים לב שאנחנו משתמשים ב- מסונכרן לחסום את אותו הדבר נתונים מקרה שאחר כך אנו קוראים לו notifyAll () שיטה.

בואו נתקן את מַקְלֵט באותה הדרך:

class SynchronizedReceiver מיישם Runnable {private logic logger log log = LoggerFactory.getLogger (SynchronizedReceiver.class); נתוני נתונים סופיים פרטיים; הודעת מחרוזת פרטית; מקבל SynchronizedReceiver ציבורי (נתוני נתונים) {this.data = נתונים; } @ עקוף ריצת חלל ציבורית () {מסונכרנת (נתונים) {נסה {data.wait (); this.message = data.receive (); } לתפוס (InterruptedException e) {log.error ("החוט הופרע", e); Thread.currentThread (). Interrupt (); }}} getMessage () מחרוזת ציבורית (הודעה חוזרת; }}

אם ניצור שוב את שני המחלקות וננסה להעביר את אותו המסר ביניהם, הכל עובד טוב, ולא יוצא שום חריג.

4. מסקנה

במאמר זה למדנו מה גורם IllegalMonitorStateException ואיך למנוע את זה.

כמו תמיד, הקוד זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found