Tại sao nên sử dụng ExecutorService cho chuỗi chạy dài?


8

Tôi muốn một đối tượng sẽ sinh ra một chuỗi daemon sẽ tiếp tục chạy trong suốt vòng đời của quá trình. Giả sử, chỉ vì lợi ích của cuộc tranh luận, đó là một luồng trong một hệ thống nhúng và nó chờ để nhận và xử lý các lệnh trên một số cổng chẩn đoán. Nhưng, nó có thể là bất cứ điều gì thực sự. Ý tưởng chính là nó đang xem thứ gì đó trong một khoảng thời gian dài; Nó không thực hiện một chuỗi các nhiệm vụ .

Trí tuệ Java thông thường nói, Không bao giờ khởi tạo Thread, Sử dụng ExecutorServicethay thế. (Ví dụ, xem câu trả lời này ) Nhưng lợi ích là gì? Sử dụng một sợi hồ bơi như một phương tiện để tạo ra một đơn sợi dài chạy dường như vô nghĩa. Làm thế nào tốt hơn nếu tôi viết nó?

class Foobar {
    public Foobar() {
        this.threadFactory = Executors.defaultThreadFactory();
        ...
    }

    public Foobar(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        ...
    }

    public void start() {
        fooThread = threadFactory.newThread(new Runnable() { ... });
        fooThread.setDaemon(true);
        fooThread.start();
    }
    ...
}

Lưu ý: câu hỏi này có vẻ giống với tôi, nhưng câu trả lời chỉ nói cách sử dụng nhóm luồng chứ không phải tại sao .



Không chắc chắn về Java, nhưng các ngôn ngữ khác thường khuyên bạn nên tránh một nhóm luồng cho bất kỳ luồng chạy dài nào. Như bạn đã nói, việc sử dụng một trong số lượng tài nguyên có hạn trong một khoảng thời gian dài sẽ không có ý nghĩa gì.
Frank Hileman

Câu trả lời:


11

Tôi nghĩ rằng "Không bao giờ" là một từ quá mạnh. Nó giống như quy tắc tối ưu hóa thứ hai: "Đừng (chưa)".

Theo tôi, lý do chính để sử dụng dịch vụ thực thi là để quản lý số lượng luồng đang chạy. Nếu bạn cho phép các lớp tùy ý tạo các luồng của riêng chúng, bạn có thể nhanh chóng tìm thấy chính mình với 1.000 luồng được liên kết với CPU (hoặc liên tục chuyển ngữ cảnh). Một dịch vụ thực thi giải quyết vấn đề đó, bằng cách cung cấp các ràng buộc về tạo luồng.

Một lý do thứ hai là việc bắt đầu một chủ đề đúng cách đòi hỏi một số suy nghĩ:

  • Daemon hay không daemon? Nhận lỗi này và bạn cần gọi System.exit()để tắt chương trình của bạn.
  • Ưu tiên gì? Rất nhiều lập trình viên của Swing nghĩ rằng họ thông minh bằng cách quay các luồng nền để xử lý các tác vụ nặng về CPU, nhưng không nhận ra rằng luồng gửi sự kiện chạy ở mức ưu tiên cao nhất và các luồng con kế thừa mức độ ưu tiên của cha mẹ.
  • Làm thế nào để đối phó với ngoại lệ chưa bị bắt?
  • Tên thích hợp là gì? Có vẻ ngớ ngẩn khi bị ám ảnh bởi một cái tên, nhưng các chủ đề có tên mục đích cung cấp cho bạn rất nhiều trợ giúp trong việc gỡ lỗi.

Điều đó nói rằng, chắc chắn có những trường hợp thích hợp để quay các luồng hơn là dựa vào nhóm luồng.

  • Tôi sẽ sử dụng nhóm luồng trong trường hợp ứng dụng của tôi đang tạo các tác vụ và tôi muốn kiểm soát cách các tác vụ đó được thực thi.
  • Tôi sẽ tạo các luồng chuyên dụng trong đó một hoặc một vài luồng được dành riêng để xử lý các sự kiện được tạo bên ngoài .

"Tạo bên ngoài" là phụ thuộc vào bối cảnh. Trường hợp cổ điển là luồng ở cuối hàng đợi tin nhắn hoặc ổ cắm, cần thăm dò hàng đợi đó và thực hiện một số hành động (có thể liên quan đến việc gửi một tác vụ đến nhóm).

Tuy nhiên, nó cũng có thể đề cập đến các sự kiện được tạo bên ngoài một mô-đun cụ thể: ví dụ: tôi cho rằng hoàn toàn hợp lý khi Log4J AsyncAppendertạo ra luồng của chính nó thay vì mong đợi ứng dụng cung cấp nhóm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.