2015-05-22 16 views
5

đoạn mã nhỏ này không bao giờ kết thúc trên jdk8u45, và sử dụng để hoàn thành đúng trên jdk8u20:ForkJoinPool, Phaser và chặn được quản lý: chúng hoạt động như thế nào so với deadlocks?

public class TestForkJoinPool { 

    final static ExecutorService pool = Executors.newWorkStealingPool(8); 
    private static volatile long consumedCPU = System.nanoTime(); 

    public static void main(String[] args) throws InterruptedException { 
     final int numParties = 100; 
     final Phaser p = new Phaser(1); 
     final Runnable r =() -> { 
      p.register(); 
      p.arriveAndAwaitAdvance(); 
      p.arriveAndDeregister(); 
     }; 

     for (int i = 0; i < numParties; ++i) { 
      consumeCPU(1000000); 
      pool.submit(r); 
     } 

     while (p.getArrivedParties() != numParties) {} 
    } 

    static void consumeCPU(long tokens) { 
     // Taken from JMH blackhole 
     long t = consumedCPU; 
     for (long i = tokens; i > 0; i--) { 
      t += (t * 0x5DEECE66DL + 0xBL + i) & (0xFFFFFFFFFFFFL); 
     } 
     if (t == 42) { 
      consumedCPU += t; 
     } 
    } 
} 

Các doc of phaser bang mà

Phasers cũng có thể được sử dụng bởi các công việc thực hiện trong một ForkJoinPool, mà sẽ đảm bảo tính song song đầy đủ để thực hiện các tác vụ khi những người khác bị chặn chờ đợi một giai đoạn để thăng tiến.

Tuy nhiên javadoc of ForkjoinPool#mangedBlock trạng thái:

Nếu chạy trong một ForkJoinPool, hồ bơi có thể đầu tiên được mở rộng để đảm bảo đủ song song

Chỉ có một có thể có. Vì vậy, tôi không chắc chắn liệu đây có phải là lỗi hay chỉ là mã không phụ thuộc vào hợp đồng của Phaser/ForkJoinPool: hợp đồng Phaser/ForkJoinPool có khó khăn như thế nào để ngăn chặn deadlocks?


cấu hình của tôi:

  1. Linux ADC 3.14.27-100.fc19.x86_64 # 1 SMP Wed 17 Tháng 12 19:36:34 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
  2. 8 lõi i7
+2

Đã nộp: https://bugs.openjdk.java.net/browse/JDK-8080939 –

+0

Ok cảm ơn. –

+1

@AlekseyShipilev Có thể có thêm thông tin chi tiết về vấn đề này: Nếu tôi xóa phần comsumeCpu() hoặc giảm số lượng mã thông báo, thử nghiệm sẽ kết thúc đúng cách. Điều tương tự nếu tôi breakpoint trong ForkJoinPool # tryCompensate và bước thủ công –

Trả lời

3

Có vẻ như sự cố của bạn xuất phát từ sự thay đổi mã ForkJoinPool giữa JDK 8u20 và 8u45.

Trong các chuỗi u20, ForkJoin luôn hoạt động trong ít nhất 200 mili giây (xem ForkJoinPool.FAST_IDLE_TIMEOUT) trước khi được khôi phục.

Trong u45, khi ForkJoinPool đã đạt đến mục tiêu song song cộng với 2 chuỗi bổ sung, luồng sẽ chết ngay khi chúng hết công việc mà không cần chờ đợi. Bạn có thể thấy sự thay đổi này trong các phương pháp awaitWork trong ForkJoinPool.java (dòng 1810):

int t = (short)(c >>> TC_SHIFT); // shrink excess spares 
    if (t > 2 && U.compareAndSwapLong(this, CTL, c, prevctl)) 
     return false; 

chương trình của bạn sử dụng nhiệm vụ Phasers để tạo công nhân thêm. Mỗi nhiệm vụ sinh ra một nhân viên đền bù mới có nghĩa là nhận nhiệm vụ được gửi tiếp theo.
Tuy nhiên, khi bạn đạt được mục tiêu song song mục tiêu + 2, nhân viên đền bù sẽ chết ngay lập tức mà không cần chờ đợi và không có cơ hội nhận nhiệm vụ sẽ được gửi ngay sau đó.

Tôi hy vọng điều này sẽ hữu ích.

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