LinkedBlockingQueue לעומת ConcurrentLinkedQueue

1. הקדמה

LinkedBlockingQueue ו ConcurrentLinkedQueue הם שני התורים המקבילים הנפוצים ביותר ב- Java. למרות ששני התורים משמשים לעתים קרובות כמבנה נתונים מקביל, ישנם מאפיינים עדינים והבדלים התנהגותיים ביניהם.

במדריך קצר זה נדון בשני התורים הללו ונסביר את הדמיון וההבדל ביניהם.

2. LinkedBlockingQueue

ה LinkedBlockingQueue הוא אופציונלי מוגבל חסימת יישום תור, כלומר ניתן להגדיר את גודל התור במידת הצורך.

בואו ניצור LinkedBlockingQueue שיכול להכיל עד 100 אלמנטים:

BlockingQueue boundedQueue = חדש LinkedBlockingQueue (100);

אנו יכולים גם ליצור ללא גבולות LinkedBlockingQueue רק על ידי אי ציון הגודל:

BlockingQueue unboundedQueue = חדש LinkedBlockingQueue ();

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

אנחנו יכולים ליצור LinkedBlockingQueue גם מאוסף קיים:

List collectionOfNumbers = Arrays.asList (1,2,3,4,5); תור BlockingQueue = חדש LinkedBlockingQueue (listOfNumbers);

ה LinkedBlockingQueue מעמד מיישם את BlockingQueue ממשק, המספק את האופי החוסם אליו.

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

ExecutorService executorService = Executors.newFixedThreadPool (1); תור LinkedBlockingQueue = חדש LinkedBlockingQueue (); executorService.submit (() -> {נסה {queue.take ();} לתפוס (InterruptedException e) {// טיפול בחריגות}});

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

תכונת החסימה של LinkedBlockingQueue קשור בעלות מסוימת. עלות זו היא משום שכל לָשִׂים או ה לקחת הפעולה היא נעילה בין המפיק או חוטי הצרכן. לכן, בתרחישים עם יצרנים וצרכנים רבים, לָשִׂים ולנקוט בפעולות יכול להיות איטי יותר.

3. ConcurrentLinkedQueue

א ConcurrentLinkedQueueהוא תור בלתי מוגבל, בטיחות חוטים ולא חוסם.

בוא ניצור ריק ConcurrentLinkedQueue:

תור ConcurrentLinkedQueue = ConcurrentLinkedQueue חדש ();

אנחנו יכולים ליצור ConcurrentLinkedQueue גם מאוסף קיים:

List collectionOfNumbers = Arrays.asList (1,2,3,4,5); תור ConcurrentLinkedQueue = ConcurrentLinkedQueue חדש (listOfNumbers);

שלא כמו א LinkedBlockingQueue,א ConcurrentLinkedQueue הוא תור שאינו חוסם. לפיכך, הוא אינו חוסם שרשור ברגע שהתור ריק. במקום זאת, הוא חוזר ריק. מכיוון שהוא לא מוגבל, הוא יזרוק א java.lang.OutOfMemoryError אם אין זיכרון נוסף להוסיף אלמנטים חדשים.

מלבד היותו לא חוסם, א ConcurrentLinkedQueue יש פונקציונליות נוספת.

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

אלמנט int = 1; ExecutorService executorService = Executors.newFixedThreadPool (2); תור ConcurrentLinkedQueue = חדש ConcurrentLinkedQueue (); Runtable offerTask = () -> queue.offer (element); ניתן לקרוא pollTask ​​= () -> {תוך (queue.peek ()! = Null) {return queue.poll (). IntValue (); } להחזיר אפס; }; executorService.submit (offerTask); Future returnElement = executorService.submit (pollTask); assertThat (returnElement.get (). intValue (), is (equalTo (element))); 

המשימה הראשונה, offerTask, מוסיף אלמנט לתור והמשימה השנייה, pollTask, אחזר אלמנט מהתור. משימת הסקר בנוסף בודק בתור אחר אלמנט כ- ConcurrentLinkedQueue אינו חוסם ויכול להחזיר א ריק ערך.

4. קווי דמיון

שניהם LinkedBlockingQueue וה ConcurrentLinkedQueue הם יישומי תורים וחולקים כמה מאפיינים משותפים. בואו נדון בדמיון בין שני התורים הללו:

  1. שניהם מיישם את תוֹר מִמְשָׁק
  2. שניהם השתמש בצמתים מקושרים כדי לאחסן את האלמנטים שלהם
  3. שניהם מתאימים לתרחישים של גישה מקבילה

5. הבדלים

למרות שלשני התורים הללו יש קווי דמיון מסוימים, ישנם גם הבדלים משמעותיים במאפיינים:

תכונהLinkedBlockingQueueConcurrentLinkedQueue
חוסם את הטבעזהו תור חוסם ומיישם את BlockingQueue מִמְשָׁקזהו תור שאינו חוסם ואינו מיישם את BlockingQueue מִמְשָׁק
גודל התורזהו תור מוגבל אופציונלי, מה שאומר שיש הוראות להגדרת גודל התור במהלך היצירהזהו תור בלתי מוגבל, ואין כל הוראה לציין את גודל התור במהלך היצירה
נעילת הטבעזה תור מבוסס נעילהזה תור ללא נעילה
אַלגוֹרִיתְםזה מיישם הנעילה שלה מבוססת על תור שני נעולים אַלגוֹרִיתְםזה מסתמך על אלגוריתם מייקל וסקוט לתורים שאינם חוסמים וללא נעילה
יישוםבתוך ה תור למנעולים מנגנון אלגוריתם, LinkedBlockingQueue משתמש בשני מנעולים שונים - putLock וה takeLock . ה לשים / לקחת פעולות משתמשות בסוג הנעילה הראשון וב- לקחת / לסקר פעולות משתמשות בסוג הנעילה האחר היא משתמשת ב- CAS (השווה והחלפה) לפעילותה
התנהגות חוסמתזהו תור חוסם. לכן, זה חוסם את שרשורי הגישה כאשר התור ריקזה לא חוסם את שרשור הגישה כאשר התור ריק וחוזר ריק

6. מסקנה

במאמר זה למדנו על LinkedBlockingQueue ו ConcurrentLinkedQueue.

ראשית, דנו בנפרד בשתי יישומי התורים הללו ובכמה מהמאפיינים שלהם. ואז ראינו את הדמיון בין שתי יישומי התורים הללו. לבסוף, בדקנו את ההבדלים בין שתי יישומי התורים הללו.

כמו תמיד, קוד המקור של הדוגמאות זמין ב- GitHub.


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