2011-12-15 25 views
9

Tôi đang sử dụng một số ThreadPoolExecutor trong Java để quản lý nhiều luồng đang chạy. Tôi đã tạo ra ThreadFactory đơn giản của riêng mình để tôi có thể cung cấp cho các chủ đề tên tốt hơn.Với ThreadPoolExecutor, làm cách nào để lấy tên của chuỗi đang chạy trong nhóm luồng?

Vấn đề là tên được đặt trong Chủ đề khi nhóm chủ đề được tạo lần đầu và không được gắn với nhiệm vụ mà nhóm chủ đề thực sự đang chạy. Tôi hiểu điều này ... Runnables và Callables của tôi - mặc dù họ có tên - thực sự là một mức độ trừu tượng xuống từ các chủ đề đang chạy của ThreadPoolExecutor.

Đã có một số câu hỏi khác về StackOverflow về việc tạo tên cho ThreadPoolExecutor nhóm luồng. (Xem How to give name to a callable Thread?How to name the threads of a thread pool in Java.)

Điều tôi muốn biết là: có ai có giải pháp tốt để giữ tên của chuỗi chủ đề hồ bơi đồng bộ với Runnable thực sự đang chạy không?

tức là Nếu tôi gọi Thread.getCurrentThread().getName() Tôi muốn nó không để trả về tên của nhóm chủ đề cấp cao nhất, mà là tên của Chủ đề có thể gọi/Runnable hiện đang chạy.

Vì đây là chủ yếu cho mục đích gỡ lỗi và ghi nhật ký, tôi đang cố gắng tránh một giải pháp liên quan đến việc đặt mã mới vào mọi Runnable có thể được gửi đến ThreadPoolExecutor - Tôi chỉ muốn đặt một số mã vào ThreadFactory hoặc quấn ThreadPoolExecutor chính nó để thay đổi được thực hiện ở một nơi. Nếu một giải pháp như vậy không tồn tại, tôi có lẽ sẽ không bận tâm vì nó không phải là nhiệm vụ quan trọng.

bắt đầu chỉnh sửa Để làm rõ, tôi biết tôi có thể đặt một Thread.currentThread().setName("my runnable name"); như dòng đầu tiên của phương pháp chạy của mỗi Runnable, nhưng tôi đang cố gắng để tránh làm điều đó. Tôi là một người cầu toàn ở đây, và tôi nhận ra nó, vì vậy tôi sẽ không bị xúc phạm nếu mọi người muốn bình luận về câu hỏi này và nói với tôi như vậy. chỉnh sửa cuối

Câu hỏi khác, tôi cho rằng, liệu mọi người nghĩ rằng đó là một ý tưởng tồi để làm một điều như vậy. Tôi có nên cảnh giác với việc cập nhật tên hồ bơi như thế này không?

Cảm ơn mọi đề xuất!

+0

"giữ tên của thread hồ bơi đồng bộ với Runnable rằng nó được thực sự chạy" -> Runnable/Callable không định nghĩa một tên, vì vậy tôi không thể hoàn toàn thấy lực đẩy của câu hỏi của bạn . Có ThreadFactory của bạn thực sự cung cấp cho mỗi thread một tên riêng biệt? – serg10

+0

Phải, mỗi Runnables và Callables của tôi thực hiện giao diện có tên, vì vậy tôi có quyền truy cập vào tên. Tôi nhận ra rằng tôi rất kén chọn rằng tôi đã triển khai một tính năng đặc biệt cho tất cả các Runnables của mình nhưng muốn tránh thêm mã bổ sung để đặt tên chuỗi theo cách thủ công. –

+1

Đã chỉnh sửa để rõ ràng, thay đổi một số "nhóm chủ đề" thành "chuỗi" và một số "chuỗi" thành "tác vụ". –

Trả lời

13

Tạo một ThreadPoolExecutor ghi đè phương thức beforeExecute.

private final ThreadPoolExecutor executor = new ThreadPoolExecutor (new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()){ 
    protected void beforeExecute(Thread t, Runnable r) { 
     t.setName(deriveRunnableName(r)); 
    } 

    protected void afterExecute(Runnable r, Throwable t) { 
     Thread.currentThread().setName(""); 
    } 

    protected <V> RunnableFuture<V> newTaskFor(final Runnable runnable, V v) { 
     return new FutureTask<V>(runnable, v) { 
      public String toString() { 
       return runnable.toString(); 
      } 
     }; 
    }; 
} 

Không chắc derveRunnableName() sẽ làm việc như thế nào một cách chính xác, có lẽ toString()?

Chỉnh sửa: Thread.currentThread() trong thực tế, luồng được đặt trong beforeExecute gọi là afterExecute. Bạn có thể tham khảo Thread.currentThread() và sau đó đặt tên trong afterExecute.Đây được ghi nhận trong javadocs

/** 
* Method invoked upon completion of execution of the given Runnable. 
* This method is invoked by the thread that executed the task. If 
* non-null, the Throwable is the uncaught <tt>RuntimeException</tt> 
* or <tt>Error</tt> that caused execution to terminate abruptly. 
* 
* <p><b>Note:</b> When actions are enclosed in tasks (such as 
* {@link FutureTask}) either explicitly or via methods such as 
* <tt>submit</tt>, these task objects catch and maintain 
* computational exceptions, and so they do not cause abrupt 
* termination, and the internal exceptions are <em>not</em> 
* passed to this method. 
* 
* <p>This implementation does nothing, but may be customized in 
* subclasses. Note: To properly nest multiple overridings, subclasses 
* should generally invoke <tt>super.afterExecute</tt> at the 
* beginning of this method. 
* 
* @param r the runnable that has completed. 
* @param t the exception that caused termination, or null if 
* execution completed normally. 
*/ 
protected void afterExecute(Runnable r, Throwable t) { } 

Sửa Các TPE sẽ quấn Runnable trong một FutureTask, vì vậy để hỗ trợ các toString phương pháp bạn có thể ghi đè lên newTaskFor và tạo riêng bọc FutureTask của bạn.

+0

Tôi đang thực sự thử một cái gì đó như thế này ngay bây giờ, đề nghị tốt như vậy. Vấn đề duy nhất là khi Runnable hoàn tất, nhóm thread vẫn có tên đó. Thật không may, phương thức afterExecute overridable không nhận được Thread trong đó Runnable được chạy. Tôi muốn có thể làm sạch nó khi tôi làm xong. –

+1

@JeffGoldberg Trong afterExecute, Thread.currentThread() là acutally thread tôi thiết lập tên trong beforeExecute. Tôi sẽ cập nhật câu trả lời của mình để chứng minh điều này. –

+0

Điều này thật tuyệt vời. Cảm ơn bạn! –

2

Đề nghị của tôi là để thử

pool.execute(new Runnable() { 
    public void run() { 
     Thread.getCurrentThread().setName("My descriptive Runnable"); 
     // do my descriptive Runnable 
    } 
});     

Bạn cũng có thể thiết lập lại tên khi bạn đã hoàn thành nếu bạn muốn.

+0

Bạn có gợi ý tôi làm điều này mỗi khi tôi thực hiện một cuộc gọi đến pool.execute hoặc tôi ghi đè lên phương thức thực thi của pool? –

+0

Giả sử bạn muốn thay đổi tên để phản ánh chủ đề đang làm gì, vâng. Lưu ý: nó sẽ thay đổi khi Runnable bắt đầu, không phải khi bạn gọi. ;) –

4

Vì vậy, tôi đã có giải pháp quản lý cả hai để đặt tên và dọn dẹp sau tên. Cảm ơn cả Peter Lawrey và John Vint vì những gợi ý của họ đã dẫn tôi đến đây. Vì không đề xuất nào xử lý hoàn toàn vấn đề của tôi nên tôi đã đoán rằng tôi sẽ đăng mã mẫu này làm câu trả lời riêng. Tôi xin lỗi nếu đó là nghi thức tồi tệ - nếu vậy, hãy cho tôi biết và tôi sẽ điều chỉnh.

Trong mã bên dưới, tôi quyết định giữ tên của ThreadPoolExecutor thread ban đầu và gắn thêm tên Runnable, sau đó trong khối cuối cùng loại bỏ tên Runnable để làm sạch, nhưng điều đó có thể dễ dàng thay đổi.

Như John Vint gợi ý, tôi muốn ghi đè phương pháp beforeExecution và sau đó ghi đè phương pháp afterExecution để dọn dẹp, nhưng afterExecution không có tay cầm cho chuỗi.

public class RunnableNameThreadPoolExecutor extends ThreadPoolExecutor { 

    /* Constructors... */ 

    @Override 
    public void execute(Runnable command) { 
     super.execute(new ManageNameRunnable(command)); 
    } 

    private class ManageNameRunnable implements Runnable { 
     private final Runnable command; 
     ManageNameRunnable(Runnable command) { 
      this.command = command; 
     } 

     public void run() { 
      String originalName = Thread.currentThread().getName(); 
      try { 
       String runnableName = getRunnableName(command); 
       Thread.currentThread().setName(originalName+ ": " + runnableName); 
       command.run(); 
      } finally { 
       Thread.currentThread().setName(originalName); 
      } 
     } 
    } 
} 
+1

bạn có mã làm việc nhiều hơn không? chẳng hạn như định nghĩa getRunnableName() và mã gọi mẫu? – peterboston

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