2009-07-22 19 views
11

Tôi gặp vấn đề mà tôi tin là mẫu tổng thể/nhân viên cổ điển và tôi đang tìm kiếm lời khuyên về việc triển khai. Dưới đây là những gì tôi hiện đang suy nghĩ về vấn đề:Mẫu/Nguyên tắc cho hàng đợi an toàn và chương trình "thạc sĩ/công nhân" trong Java

Có một "hàng đợi" toàn cầu thuộc loại nào đó và đó là nơi trung tâm nơi "công việc phải làm" được lưu giữ. Có lẽ hàng đợi này sẽ được quản lý bởi một loại đối tượng "chính". Chủ đề sẽ được sinh ra để đi tìm việc phải làm, và khi họ tìm việc phải làm, họ sẽ nói với chủ nhân (bất cứ điều gì) để "thêm cái này vào hàng đợi công việc phải làm".

Chủ nhân, có lẽ trong một khoảng thời gian, sẽ sinh ra các chủ đề khác thực sự thực hiện công việc cần thực hiện. Khi một thread hoàn thành công việc của nó, tôi muốn nó thông báo cho chủ nhân rằng công việc đã hoàn thành. Sau đó, tổng thể có thể xóa tác phẩm này khỏi hàng đợi.

Tôi đã thực hiện một số lượng hợp lý các chương trình chuỗi trong Java trong quá khứ, nhưng tất cả đã ở trước JDK 1.5 và do đó tôi không quen với các API mới thích hợp để xử lý trường hợp này. Tôi hiểu rằng JDK7 sẽ có ngã ba, và đó có thể là một giải pháp cho tôi, nhưng tôi không thể sử dụng sản phẩm truy cập sớm trong dự án này.

Những vấn đề, như tôi đã nhìn thấy chúng, là:

1) làm thế nào để có "đề làm công việc" truyền đạt lại cho các bậc thầy nói với họ rằng công việc của họ là đầy đủ và rằng các bậc thầy bây giờ có thể loại bỏ các làm việc từ hàng đợi

2) cách bảo đảm chính hiệu quả rằng công việc chỉ được lên lịch một lần. Ví dụ: giả sử hàng đợi này có hàng triệu mục và muốn nói với một nhân viên "hãy làm 100 điều này". Cách hiệu quả nhất để đảm bảo rằng khi nó lên kế hoạch làm việc cho công nhân tiếp theo, nó sẽ là "100 điều tiếp theo" chứ không phải "100 điều tôi đã lên lịch"?

3) chọn cấu trúc dữ liệu thích hợp cho hàng đợi. Suy nghĩ của tôi ở đây là "chủ đề tìm việc phải làm" có khả năng tìm ra công việc tương tự để làm nhiều hơn một lần, và họ sẽ gửi một thông điệp tới vị thầy nói "đây là công việc", và thầy sẽ nhận ra rằng tác phẩm có đã được lên lịch và do đó nên bỏ qua thông báo. Tôi muốn đảm bảo rằng tôi chọn cấu trúc dữ liệu phù hợp để tính toán này rẻ nhất có thể.

Theo truyền thống, tôi đã thực hiện điều này trong cơ sở dữ liệu, theo kiểu máy trạng thái hữu hạn, làm việc "nhiệm vụ" từ đầu đến cuối. Tuy nhiên, trong vấn đề này, tôi không muốn sử dụng một cơ sở dữ liệu vì khối lượng cao và biến động của hàng đợi. Ngoài ra, tôi muốn giữ nó càng nhẹ càng tốt. Tôi không muốn sử dụng bất kỳ máy chủ ứng dụng nào nếu điều đó có thể tránh được. Rất có thể vấn đề này tôi đang mô tả là một vấn đề phổ biến với một tên nổi tiếng và các giải pháp được chấp nhận, nhưng tôi, với mức độ không phải là CS, không biết điều này được gọi là gì (tức là hãy nhẹ nhàng).

Cảm ơn bất kỳ và tất cả các con trỏ.

+0

bạn cũng có thể muốn xem http://lambda-the-ultimate.org/node/3521 "Một ngã ba/khung công tác Java" –

Trả lời

7

Theo như tôi hiểu yêu cầu của bạn, bạn cần ExecutorService. ExecutorService có

submit(Callable task) 

phương thức trả về giá trị là Future. Tương lai là một cách ngăn chặn để giao tiếp lại từ công nhân để làm chủ. Bạn có thể dễ dàng mở rộng cơ chế này để hoạt động không đồng bộ. Và có, ExecutorService cũng duy trì hàng đợi công việc như ThreadPoolExecutor. Vì vậy, bạn không cần phải bận tâm về việc lên lịch, trong hầu hết các trường hợp. gói java.util.concurrent đã có triển khai hiệu quả luồng an toàn của luồng (hàng đợi ConcurrentLinked - nonblocking và LinkedBlockedQueue - blocking).

+0

Để thêm vào những gì @dotsid gợi ý, tôi sẽ chỉ ra rằng thư viện chuẩn này thực hiện rất nhiều, nếu không phải tất cả, OP yêu cầu và nó rất đơn giản để sử dụng và nó hoạt động. Bạn có thể mở rộng lên đến 100 hoặc hàng nghìn tác vụ mà không cần nỗ lực nhiều. –

+0

Cảm ơn mọi người vì những câu trả lời chu đáo. Tôi không chắc đây có phải là câu trả lời "kinh điển" hay không, nhưng cuối cùng, sau khi đọc cuốn sách Goetz, những gì tôi đã kết thúc với cái nhìn rất giống câu trả lời này. –

4

Khám phá java.util.concurrent trong thư viện Java.

Tùy thuộc vào ứng dụng của bạn, nó có thể đơn giản như cobbling cùng với một số hàng đợi chặn và một ThreadPoolExecutor.

Ngoài ra, sách Java Concurrency in Practice của Brian Goetz có thể hữu ích.

4

Trước tiên, tại sao bạn muốn giữ các mục sau khi một nhân viên bắt đầu thực hiện chúng?Thông thường, bạn sẽ có một hàng đợi công việc và một nhân viên lấy các vật phẩm ra khỏi hàng đợi này. Điều này cũng sẽ giải quyết vấn đề "làm thế nào tôi có thể ngăn chặn công nhân nhận được cùng một mục".

Để câu hỏi của bạn:

1) làm thế nào để có "đề làm công việc " truyền đạt lại cho các bậc thầy nói với họ rằng công việc của họ là đầy đủ và rằng các bậc thầy bây giờ có thể tháo làm việc từ hàng đợi

thầy có thể lắng nghe những người lao động bằng cách sử dụng listener/observer pattern

2) làm thế nào để có hiệu quả bảo đảm chủ rằng công việc chỉ được thực hiện được lên lịch một lần. Ví dụ: giả sử hàng đợi này có một triệu mục và muốn yêu cầu một nhân viên "làm những việc này 100 điều". Cách bảo đảm hiệu quả nhất khi nó lịch làm việc cho nhân viên tiếp theo là gì, nó nhận được "100 điều tiếp theo" và không phải là "100 điều tôi đã có được lên lịch"?

Xem ở trên. Tôi sẽ để công nhân kéo các vật phẩm ra khỏi hàng đợi.

3) chọn dữ liệu thích hợp cấu trúc cho hàng đợi. Suy nghĩ của tôi ở đây là "chủ đề tìm việc để làm" có khả năng tìm thấy cùng một công việc để làm nhiều hơn một lần, và họ muốn gửi một thông điệp đến chủ nói "đây là công việc" và chủ sẽ nhận ra rằng công việc đã được lập lịch và do đó cần bỏ qua thông báo. Tôi muốn đảm bảo rằng tôi chọn đúng cấu trúc dữ liệu sao cho tính toán này có giá rẻ hơn càng tốt.

Có Triển khai một blocking queue kể từ Java 5

+0

Cảm ơn mọi người đã trả lời. Tim, với câu hỏi đầu tiên của bạn, câu hỏi hay nhất: Tôi tin rằng tôi cần giữ các mục trên hàng đợi vì "chuỗi công việc đi ra ngoài và tìm việc cần làm" cần phải biết công việc đã được lên lịch nào. Ví dụ cụ thể, hãy tưởng tượng một chương trình phải ra ngoài và tìm "tệp cũ để di chuyển". Chủ đề tìm thấy chúng, thêm chúng vào hàng đợi. Nhưng trên các lần chạy tiếp theo, nếu các tệp đó chưa được di chuyển, chuỗi "công cụ tìm" sẽ tìm thấy cùng một tệp. Có ý nghĩa? Cách thích hợp hơn để đối phó với vấn đề đó? Cảm ơn bạn lần nữa. –

+0

Có thể bạn không cần phải bận tâm về nó. Có một chất lượng tốt về các hệ thống không đồng bộ - tính ngẫu nhiên. Hệ thống nên được bảo vệ chống xử lý thông điệp kép (nói bằng toán f (x) phải bằng f (f (x)), vì vậy trạng thái hệ thống không thay đổi nếu một thông báo được xử lý hai lần). Ví dụ của bạn là ví dụ tốt về tính ngẫu nhiên trong hệ thống. Chúng tôi có thể chuyển thông điệp về một tệp cụ thể hai lần cho công nhân và không có gì xấu xảy ra. Nếu tệp đã được di chuyển, chúng tôi chỉ cần bỏ qua tác vụ. –

+0

Bạn có thể xác định hàng đợi công việc và bên cạnh danh sách trong công việc này. Khi một chuỗi công nhân lấy một mục từ hàng đợi, bạn thêm nó vào danh sách đang làm việc. Khi công nhân được thực hiện, bạn có thể xóa nó khỏi danh sách trong công việc. Nếu một mục được gửi dưới dạng mục mới, bạn có thể kiểm tra xem mục đó đã có trong hàng đợi hay trong danh sách thì bỏ qua nó. –

0

Nếu bạn đang mở với ý tưởng của mùa xuân, sau đó kiểm tra dự án tích hợp mùa xuân của họ. Nó cung cấp cho bạn tất cả các hàng đợi/thread-pool boilerplate ra khỏi hộp và để bạn tập trung vào logic nghiệp vụ. Cấu hình được giữ ở mức tối thiểu bằng cách sử dụng @annotations.

btw, Goetz rất tốt.

1

Đừng quên Jini và Javaspaces. Những gì bạn mô tả âm thanh rất giống với mô hình sản xuất/người tiêu dùng cổ điển mà các kiến ​​trúc dựa trên không gian nổi trội.

Nhà sản xuất sẽ ghi công việc vào không gian. 1 hoặc nhiều người tiêu dùng sẽ thực hiện các công việc (theo một giao dịch) và làm việc trên song song, và sau đó viết kết quả lại. Vì nó nằm trong một giao dịch, nếu một vấn đề xảy ra, công việc đó sẽ được cung cấp lại cho người tiêu dùng khác.

Bạn có thể mở rộng quy mô này một cách tầm thường bằng cách thêm nhiều người tiêu dùng hơn. Điều này làm việc đặc biệt tốt khi người tiêu dùng là máy ảo riêng biệt và bạn mở rộng trên mạng.

0

Điều này không có vẻ giống như vấn đề của nhân viên chính, mà là một khách hàng chuyên biệt trên một luồng. Cho rằng bạn có rất nhiều chủ đề nhặt rác và không có nhiều đơn vị xử lý, nó có thể đáng giá chỉ đơn giản là thực hiện việc vượt qua và sau đó là một máy tính. Bằng cách lưu trữ các mục công việc trong một Set, ràng buộc duy nhất sẽ loại bỏ các bản sao. Việc vượt qua thứ hai có thể gửi tất cả các công việc cho một ExecutorService để thực hiện quá trình song song.

Mô hình công nhân chủ thường giả định rằng nhà cung cấp dữ liệu có tất cả công việc và cung cấp cho chủ nhân quản lý. Thạc sĩ kiểm soát việc thực hiện công việc và giao dịch với tính toán phân tán, time-outs, thất bại, retries, vv Một ngã ba tham gia trừu tượng là một đệ quy chứ không phải là nhà cung cấp dữ liệu lặp đi lặp lại. Bản tóm tắt giảm bản đồ là một bậc thầy nhiều bước hữu ích trong một số trường hợp nhất định.

Ví dụ tốt về nhân viên chính là các vấn đề song song tầm thường, chẳng hạn như tìm số nguyên tố. Khác là một tải dữ liệu mà mỗi mục là độc lập (xác thực, biến đổi, giai đoạn). Sự cần thiết phải xử lý một bộ làm việc đã biết, xử lý các lỗi, vv là những gì làm cho một mô hình công nhân chủ khác với một nhóm luồng. Đây là lý do tại sao một bậc thầy phải được kiểm soát và đẩy các đơn vị làm việc ra, trong khi một threadpool cho phép công nhân để kéo công việc từ một hàng đợi được chia sẻ.

Các vấn đề liên quan