Tôi đang làm việc để thiết kế một ứng dụng bao gồm ba phần:
- một luồng duy nhất theo dõi các sự kiện nhất định xảy ra (tạo tệp, yêu cầu bên ngoài, v.v.)
- N luồng công nhân phản ứng với các sự kiện này bằng cách xử lý chúng (mỗi công nhân xử lý và tiêu thụ một sự kiện duy nhất và quá trình xử lý có thể mất thời gian khác nhau)
- một bộ điều khiển quản lý các luồng đó và xử lý lỗi (khởi động lại các luồng, ghi nhật ký kết quả)
Mặc dù điều này khá cơ bản và không khó thực hiện, tôi tự hỏi đâu là cách "đúng" để làm điều đó (trong trường hợp cụ thể này trong Java, nhưng các câu trả lời trừu tượng cao hơn cũng được đánh giá cao). Hai chiến lược xuất hiện trong tâm trí:
Observer / Observable: Chuỗi xem được quan sát bởi bộ điều khiển. Trong trường hợp có sự kiện xảy ra, bộ điều khiển sau đó sẽ được thông báo và có thể gán tác vụ mới cho luồng miễn phí từ nhóm luồng được lưu trong bộ nhớ cache có thể sử dụng lại (hoặc chờ và lưu trữ các tác vụ trong hàng đợi FIFO nếu tất cả các luồng hiện đang bận). Các luồng công nhân thực hiện Callable và trả về thành công với kết quả (hoặc giá trị boolean) hoặc trả về có lỗi, trong trường hợp đó, bộ điều khiển có thể quyết định nên làm gì (tùy thuộc vào bản chất của lỗi đã xảy ra).
Nhà sản xuất / Người tiêu dùng : Chuỗi xem chia sẻ BlockingQueue với bộ điều khiển (hàng đợi sự kiện) và bộ điều khiển chia sẻ hai với tất cả các công nhân (hàng đợi tác vụ và hàng đợi kết quả). Trong trường hợp của một sự kiện, luồng xem sẽ đặt một đối tượng tác vụ vào hàng đợi sự kiện. Bộ điều khiển nhận các tác vụ mới từ hàng đợi sự kiện, xem xét chúng và đặt chúng vào hàng đợi tác vụ. Mỗi công nhân chờ đợi các nhiệm vụ mới và nhận / tiêu thụ chúng từ hàng đợi nhiệm vụ (lần đầu tiên được phục vụ trước, được quản lý bởi chính hàng đợi), đưa kết quả hoặc lỗi trở lại vào hàng đợi kết quả. Cuối cùng, bộ điều khiển có thể truy xuất kết quả từ hàng đợi kết quả và thực hiện theo các bước trong trường hợp có lỗi.
Kết quả cuối cùng của cả hai phương pháp đều tương tự nhau, nhưng chúng đều có những khác biệt nhỏ:
Với Người quan sát, việc kiểm soát các luồng là trực tiếp và mỗi tác vụ được quy cho một công nhân sinh sản mới cụ thể. Chi phí để tạo chủ đề có thể cao hơn, nhưng không nhiều nhờ vào nhóm chủ đề được lưu trữ. Mặt khác, mẫu Observer được thu gọn thành một Observer duy nhất thay vì nhiều, đó không chính xác là mẫu được thiết kế cho.
Chiến lược xếp hàng dường như dễ dàng mở rộng hơn, ví dụ: thêm nhiều nhà sản xuất thay vì một nhà sản xuất đơn giản và không yêu cầu bất kỳ thay đổi nào. Nhược điểm là tất cả các luồng sẽ chạy vô thời hạn, ngay cả khi không thực hiện bất kỳ công việc nào, và xử lý lỗi / kết quả trông không thanh lịch như trong giải pháp đầu tiên.
Điều gì sẽ là cách tiếp cận phù hợp nhất trong tình huống này và tại sao? Tôi đã gặp khó khăn khi tìm câu trả lời cho câu hỏi này trực tuyến, vì hầu hết các ví dụ chỉ xử lý các trường hợp rõ ràng, như cập nhật nhiều cửa sổ với giá trị mới trong trường hợp Observer hoặc xử lý với nhiều người tiêu dùng và nhà sản xuất. Bất kỳ đầu vào được đánh giá rất cao.