מבוא למחליף ב- Java

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

במדריך זה נבדוק java.util.concurrent.Exchanger. זה עובד כנקודה משותפת לשני שרשורים ב- Java להחלפת אובייקטים ביניהם.

2. מבוא למחליף

ה חַלְפָן בכיתה ב- Java ניתן להשתמש כדי לשתף אובייקטים בין שני שרשורים מהסוג ט. הכיתה מספקת רק שיטה עמוסה מדי החלפה (T t).

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

בואו נבחן דוגמה כדי להבין את חילופי המסרים בין שני שרשורים עם חַלְפָן:

@Test הציבור בטל givenThreads_whenMessageExchanged_thenCorrect () {מחליף מחליף = מחליף חדש (); ניתן להפעיל taskA = () -> {נסה {String message = exchanger.exchange ("מ- A"); assertEquals ("מ- B", הודעה); } לתפוס (InterruptedException e) {Thread.currentThread.interrupt (); לזרוק RuntimeException חדש (ה); }}; ריצה משימה B = () -> {נסה {String message = exchanger.exchange ("מ- B"); assertEquals ("מ- A", הודעה); } לתפוס (InterruptedException e) {Thread.currentThread.interrupt (); לזרוק RuntimeException חדש (ה); }}; CompletableFuture.allOf (runAsync (taskA), runAsync (taskB)). להצטרף (); }

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

@Test הציבור בטל givenThread_WhenExchangedMessage_thenCorrect () זורק InterruptedException {מחליף מחליף = מחליף חדש (); Runnerable Runner = () -> {נסה {String message = exchanger.exchange ("מ- runner"); assertEquals ("לרץ", הודעה); } לתפוס (InterruptedException e) {Thread.currentThread.interrupt (); לזרוק RuntimeException חדש (ה); }}; תוצאה של CompletableFuture = CompletableFuture.runAsync (רץ); מחרוזת msg = exchanger.exchange ("לרץ"); assertEquals ("מאת runner", msg); result.join (); }

שים לב, אנחנו צריכים להתחיל את רָץ השחיל שיחה ראשונה ומאוחרת לְהַחלִיף() בחוט הראשי.

כמו כן, שים לב שהקריאה לשרשור הראשון עשויה להפסיק זמן אם השרשור השני לא יגיע לנקודת ההחלפה בזמן. כמה זמן החוט הראשון צריך לחכות ניתן לשלוט באמצעות עומס יתר exchange (T t, פסק זמן ארוך, TimeUnit timeUnit).

3. אין חילופי נתונים של GC

חַלְפָן יכול לשמש ליצירת דוגמאות של צינורות עם העברת נתונים משרשור אחד למשנהו. בחלק זה ניצור ערימה פשוטה של ​​שרשורים המעבירים נתונים זה לזה ברציפות כצינור.

@Test ציבורי בטל givenData_whenPassedThrough_thenCorrect () זורק InterruptedException {מחליף readerExchanger = מחליף חדש (); חַלְפָן writerExchanger = מחליף חדש (); קורא ניתן להריצה = () -> {ReaderBuffer בתור = ConcurrentLinkedQueue חדש (); בעוד (נכון) {readerBuffer.add (UUID.randomUUID (). toString ()); אם (readerBuffer.size ()> = BUFFER_SIZE) {readerBuffer = readerExchanger.exchange (readerBuffer); }}}; מעבד ניתן להריצה = () -> {תור מעבד תור = חדש ConcurrentLinkedQueue (); תור writerBuffer = ConcurrentLinkedQueue חדש (); processorBuffer = readerExchanger.exchange (processorBuffer); בעוד (נכון) {writerBuffer.add (processorBuffer.poll ()); אם (processorBuffer.isEmpty ()) {processorBuffer = readerExchanger.exchange (processorBuffer); writerBuffer = writerExchanger.exchange (writerBuffer); }}}; כותב שניתן להפעיל = () -> {תור כותב Buffer = ConcurrentLinkedQueue חדש (); writerBuffer = writerExchanger.exchange (writerBuffer); בעוד (נכון) {System.out.println (writerBuffer.poll ()); אם (writerBuffer.isEmpty ()) {writerBuffer = writerExchanger.exchange (writerBuffer); }}}; CompletableFuture.allOf (runAsync (קורא), runAsync (מעבד), runAsync (כותב)). להצטרף (); }

הנה, יש לנו שלושה שרשורים: קוֹרֵא, מעבד, ו סוֹפֵר. יחד הם עובדים כצינור יחיד המחליף נתונים ביניהם.

ה מחליף קורא משותף בין קוֹרֵא וה מעבד חוט, ואילו מחליף מחליף משותף בין מעבד וה סוֹפֵר פְּתִיל.

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

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

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

4. מסקנה

אז למדנו מה חַלְפָן נמצא בג'אווה, איך זה עובד, וראינו כיצד להשתמש ב- חַלְפָן מעמד. כמו כן, יצרנו צינור והדגמנו חילופי נתונים ללא GC בין שרשורים.

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


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