2015-12-01 17 views
6

Có thể định cấu hình ForkJoinPool để sử dụng 1 chuỗi thực thi không?Cách cấu hình một ForkJoinPool đơn luồng?

Tôi đang thực thi mã gọi Random bên trong một ForkJoinPool. Mỗi khi nó chạy, tôi kết thúc với hành vi thời gian chạy khác nhau, làm cho nó khó khăn để điều tra hồi quy.

Tôi muốn bộ mã hóa cung cấp chế độ "gỡ lỗi" và "giải phóng". Chế độ "gỡ lỗi" sẽ định cấu hình Random với một hạt cố định và ForkJoinPool với một chuỗi thực hiện duy nhất. Chế độ "phát hành" sẽ sử dụng các hạt giống Random do hệ thống cung cấp và sử dụng số chủ đề mặc định là ForkJoinPool.

Tôi đã thử định cấu hình ForkJoinPool với tính song song 1, nhưng nó sử dụng 2 luồng (main và chuỗi công nhân thứ hai). Bất kỳ ý tưởng?

+0

Có một tốt hơn thực hiện ngẫu nhiên cho chế độ phát hành https://docs.oracle.com/javase/tutorial/essential/concurrency/threadlocalrandom.html – zapl

+0

@zapl Tôi đã sử dụng 'ThreadLocalRandom' cho chế độ phát hành. Câu hỏi này không phải là cải thiện hiệu suất. Đó là về việc cải thiện tính năng gỡ lỗi dễ dàng bằng cách định cấu hình 'ForkJoinPool' để sử dụng một chuỗi đơn. – Gili

+0

Bạn đã thử đặt song song thành 0? – pvg

Trả lời

7

Vì vậy, hóa ra tôi đã sai.

Khi bạn định cấu hình ForkJoinPool với parallelism đặt thành 1, chỉ một chủ đề thực hiện các tác vụ. Chủ đề main bị chặn trên ForkJoin.get(). Nó không thực sự thực hiện bất kỳ nhiệm vụ nào.

Điều đó nói rằng, hóa ra là nó thực sự phức tạp cung cấp hành vi xác định. Dưới đây là một số vấn đề tôi phải sửa:

  • ForkJoinPool được thực hiện nhiệm vụ sử dụng đề người lao động khác nhau (với tên gọi khác nhau) nếu các sợi nhân trở nên nhàn rỗi thời gian đủ dài. Ví dụ, nếu chủ đề chính bị treo trên một điểm ngắt, thì chuỗi công nhân sẽ trở nên nhàn rỗi và tắt. Khi tôi tiếp tục thực hiện, ForkJoinThread sẽ quay lên một chuỗi công nhân mới có tên khác. Để giải quyết vấn đề này, tôi đã phải provide a custom ForkJoinWorkerThreadFactory implementation that returns null if the ForkJoinPool already has a live worker (điều này ngăn không cho nhóm tạo nhiều công nhân). Tôi cũng đã đảm bảo rằng mã của tôi đã trả về cùng một trường hợp Random ngay cả khi một chuỗi công nhân tắt và quay lại.
  • Các bộ sưu tập có thứ tự lặp không xác định như HashMap hoặc HashSet dẫn đến các phần tử lấy các số ngẫu nhiên theo thứ tự khác nhau trên mọi lần chạy. Tôi đã sửa lỗi này bằng cách sử dụng LinkedHashMapLinkedHashSet.
  • Đối tượng có triển khai hashCode() không xác định, chẳng hạn như Enum.hashCode(). Tôi quên những vấn đề này gây ra nhưng tôi sửa chữa nó bằng cách tính toán hashCode() bản thân mình thay vì dựa vào phương pháp được xây dựng trong.

Đây là một thực hiện mẫu ForkJoinWorkerThreadFactory:

class MyForkJoinWorkerThread extends ForkJoinWorkerThread 
{ 
    MyForkJoinWorkerThread(ForkJoinPool pool) 
    { 
     super(pool); 
     // Change thread name after ForkJoinPool.registerWorker() does the same 
     setName("DETERMINISTIC_WORKER"); 
    } 
} 

ForkJoinWorkerThreadFactory factory = new ForkJoinWorkerThreadFactory() 
{ 
    private WeakReference<Thread> currentWorker = new WeakReference<>(null); 

    @Override 
    public synchronized ForkJoinWorkerThread newThread(ForkJoinPool pool) 
    { 
     // If the pool already has a live thread, wait for it to shut down. 
     Thread thread = currentWorker.get(); 
     if (thread != null && thread.isAlive()) 
     { 
      try 
      { 
       thread.join(); 
      } 
      catch (InterruptedException e) 
      { 
       log.error("", e); 
      } 
     } 
     ForkJoinWorkerThread result = new MyForkJoinWorkerThread(pool); 
     currentWorker = new WeakReference<>(result); 
     return result; 
    } 
}; 
+0

Tốt. Nó sẽ hữu ích cho người khác nếu bạn đăng một số khối mã quan trọng liên quan đến ThreadFactory. –

+0

Tuyệt vời. Đặc biệt là phần mở rộng chỉ công nhân. –

0

Chủ đề chính luôn là luồng đầu tiên mà ứng dụng của bạn sẽ tạo. Vì vậy, khi bạn tạo một ForkJoinPool với parallelism của 1, bạn đang tạo một chuỗi khác. Có hiệu lực sẽ có hai luồng trong ứng dụng ngay bây giờ (vì bạn đã tạo một chủ đề pool).

Nếu bạn chỉ cần một chuỗi là Chính, bạn có thể thực thi mã theo thứ tự (và hoàn toàn không song song).

+0

Tôi đã biết điều này. Để làm rõ, tôi cần để có thể thay đổi số lượng các chủ đề được sử dụng bởi 'ForkJoinPool' mà không thay đổi phần còn lại của mã của tôi. Đề xuất của bạn để thực thi mã theo thứ tự (bán phá giá 'ForkJoinPool') ngụ ý thay đổi mức thiết kế mỗi khi tôi muốn chuyển đổi giữa các chế độ" gỡ rối "và" giải phóng ". – Gili

+0

Bạn có thể cập nhật câu hỏi của mình bằng một mã nhỏ thể hiện sự cố của bạn không? – tuxdna

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