Ví dụ SynchronousQueue trong Java - giải quyết vấn đề Nhà sản xuất Người tiêu dùng
SynchronousQueue là một loại BlockingQueue đặc biệt trong đó mỗi thao tác chèn phải chờ lệnh xóa tương ứng trong một luồng khác và ngược lại. Khi bạn gọi phương thức put() trên SynchronousQueue, nó sẽ chặn cho đến khi một luồng khác lấy phần tử đó từ nó. Theo đó, nếu một luồng khác cố gắng loại bỏ một phần tử khỏi nó và phần tử đó không có ở đó thì luồng đó sẽ chặn cho đến khi luồng kia đưa phần tử đó vào hàng đợi. Bạn có thể hình dung SynchronousQueue như một vận động viên ( sợi dây ) chạy với ngọn đuốc Olympic, anh ta chạy với ngọn đuốc (vật đang được truyền qua) và chuyền nó cho một vận động viên khác đang đợi ở phía bên kia. Nếu để ý đến cái tên, bạn sẽ hiểu SynchronousQueue được đặt tên như vậy là có lý do, nó truyền dữ liệu một cách đồng bộ sang một luồng khác ; nó đợi ai đó lấy dữ liệu thay vì chỉ đưa dữ liệu vào và thoát ra (một hoạt động không đồng bộ). Nếu bạn quen thuộc với CSP và Ada thì bạn biết rằng hàng đợi được đồng bộ hóa tương tự như cuộc gặp gỡ của các luồng. Chúng rất phù hợp cho các cấu trúc chuyển giao điều khiển trong đó một đối tượng chạy trong một luồng phải đồng bộ hóa với một đối tượng trong một luồng khác để truyền một số thông tin, sự kiện hoặc tác vụ tới nó. Trong các hướng dẫn lập trình đa luồng trước đây, chúng ta đã học cách giải quyết vấn đề nhà sản xuất-người tiêu dùng bằng cách sử dụng các phương thức chờ và thông báo cũng như BlockingQueue . Bây giờ chúng ta sẽ tìm hiểu cách áp dụng mẫu nhà sản xuất-người tiêu dùng bằng SynchronousQueue. Lớp này cũng hỗ trợ hành vi công bằng trong việc ra lệnh chờ đợi của các luồng sản xuất và tiêu dùng. Theo mặc định, thứ tự này không được đảm bảo. Tuy nhiên, hàng đợi được tạo bằng các thuộc tính hợp lý sẽ đảm bảo quyền truy cập cho các luồng trong hàng đợi FIFO (Firs In First Out).Nhà sản xuất/Người tiêu dùng sử dụng SynchronousQueue trong Java.

import java.util.concurrent.SynchronousQueue; /** * Java Program to solve Producer Consumer problem using SynchronousQueue. A * call to put() will block until there is a corresponding thread to take() that * element. * * @author Javin Paul */ public class SynchronousQueueDemo{ public static void main(String args[]) { final SynchronousQueue
queue = new SynchronousQueue
(); Thread producer = new Thread("PRODUCER") { public void run() { String event = "FOUR"; try { queue.put(event); // thread will block here System.out.printf("[%s] published event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; producer.start(); // starting publisher thread Thread consumer = new Thread("CONSUMER") { public void run() { try { String event = queue.take(); // thread will block here System.out.printf("[%s] consumed event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; consumer.start(); // starting consumer thread } } Output: [CONSUMER] consumed event : FOUR [PRODUCER] published event : FOUR
new SynchronousQueue(boolean fair).
Những điều bạn cần nhớ về SynchronousQueue trong Java.
Dưới đây là một số thuộc tính quan trọng của loại hàng đợi chặn đặc biệt này trong Java. Việc truyền dữ liệu từ luồng này sang luồng khác một cách đồng bộ là rất hữu ích. Hàng đợi này không có dung lượng và bị chặn cho đến khi một luồng khác giải phóng nó.
- Các khối SynchronousQueue và cho đến khi một luồng sẵn sàng lấy dữ liệu, một luồng khác sẽ cố gắng đưa dữ liệu vào.
- SynchronousQueue không có âm lượng. Tức là nó không chứa dữ liệu.
- SynchronousQueue được sử dụng để triển khai chiến lược xếp hàng chuyển tiếp, trong đó một luồng chuyển điều khiển đến một luồng đang chờ hoặc tạo một luồng mới nếu được phép, nếu không thì điều khiển sẽ không được chuyển.
- Hàng đợi này không cho phép dữ liệu null. Việc cố gắng thêm phần tử null sẽ tạo ra ngoại lệ NullPointerException .
- Nếu bạn sử dụng các phương thức khác từ Bộ sưu tập (chẳng hạn như chứa), SynchronousQueue sẽ hoạt động giống như một bộ sưu tập trống.
- Bạn không thể sử dụng phương thức xem nhanh của SynchronousQueue vì phần tử chỉ tồn tại khi bạn cố xóa nó; Ngoài ra, bạn sẽ không thể chèn các phần tử (sử dụng bất kỳ phương thức nào) cho đến khi một luồng khác cố gắng xóa nó.
- Bạn sẽ không thể sử dụng iterator cho SynchronousQueue vì... nó không có phần tử.
- SynchronousQueue có thể được tạo bằng các quy tắc công bằng, trong đó quyền truy cập vào các luồng được đảm bảo theo thứ tự FIFO.
GO TO FULL VERSION