ExecutorService ที่ขัดขวางงานหลังจากหมดเวลา


95

ฉันกำลังมองหาการใช้งานExecutorServiceที่สามารถกำหนดระยะหมดเวลาได้ งานที่ส่งไปยัง ExecutorService ถูกขัดจังหวะหากใช้เวลานานกว่าการหมดเวลาในการรัน การใช้สัตว์ร้ายเช่นนี้ไม่ใช่เรื่องยาก แต่ฉันสงสัยว่าจะมีใครรู้ถึงการใช้งานที่มีอยู่หรือไม่

นี่คือสิ่งที่ฉันคิดขึ้นจากการสนทนาด้านล่าง มีคำแนะนำอะไรมั้ย?

import java.util.List;
import java.util.concurrent.*;

public class TimeoutThreadPoolExecutor extends ThreadPoolExecutor {
    private final long timeout;
    private final TimeUnit timeoutUnit;

    private final ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
    private final ConcurrentMap<Runnable, ScheduledFuture> runningTasks = new ConcurrentHashMap<Runnable, ScheduledFuture>();

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    @Override
    public void shutdown() {
        timeoutExecutor.shutdown();
        super.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        timeoutExecutor.shutdownNow();
        return super.shutdownNow();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        if(timeout > 0) {
            final ScheduledFuture<?> scheduled = timeoutExecutor.schedule(new TimeoutTask(t), timeout, timeoutUnit);
            runningTasks.put(r, scheduled);
        }
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        ScheduledFuture timeoutTask = runningTasks.remove(r);
        if(timeoutTask != null) {
            timeoutTask.cancel(false);
        }
    }

    class TimeoutTask implements Runnable {
        private final Thread thread;

        public TimeoutTask(Thread thread) {
            this.thread = thread;
        }

        @Override
        public void run() {
            thread.interrupt();
        }
    }
}

นั่นคือ 'เวลาเริ่มต้น' ของการหมดเวลาของการส่งหรือไม่? หรือเวลาที่งานเริ่มดำเนินการ?
Tim Bender

คำถามที่ดี. เมื่อเริ่มดำเนินการ คงจะใช้protected void beforeExecute(Thread t, Runnable r)เบ็ด.
Edward Dale

@ scompt.com คุณยังคงใช้โซลูชันนี้อยู่หรือถูก superceded
Paul Taylor

@PaulTaylor งานที่ฉันใช้โซลูชันนี้ได้รับการบังคับ :-)
Edward Dale

ฉันต้องการสิ่งนี้จริงๆยกเว้น a) ฉันต้องการบริการจัดตารางเวลาหลักของฉันเพื่อเป็นเธรดพูลที่มีเธรดบริการเดียวเนื่องจากต้องการให้งานของฉันดำเนินการพร้อมกันอย่างเคร่งครัดและ b) ฉันต้องสามารถระบุระยะหมดเวลาสำหรับแต่ละงานที่ เวลาส่งงาน ฉันได้ลองใช้สิ่งนี้เป็นจุดเริ่มต้น แต่กำลังขยาย ScheduledThreadPoolExecutor แต่ฉันไม่เห็นวิธีที่จะได้รับระยะหมดเวลาที่ระบุซึ่งจะระบุในเวลาส่งงานจนถึงเมธอด beforeExecute ข้อเสนอแนะใด ๆ ขอขอบคุณ!
Michael Ellis

คำตอบ:


91

คุณสามารถใช้ScheduledExecutorServiceสำหรับสิ่งนี้ ก่อนอื่นคุณต้องส่งเพียงครั้งเดียวเพื่อเริ่มต้นทันทีและรักษาอนาคตที่สร้างขึ้น หลังจากนั้นคุณสามารถส่งงานใหม่ที่จะยกเลิกอนาคตที่เก็บไว้หลังจากช่วงเวลาหนึ่ง

 ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); 
 final Future handler = executor.submit(new Callable(){ ... });
 executor.schedule(new Runnable(){
     public void run(){
         handler.cancel();
     }      
 }, 10000, TimeUnit.MILLISECONDS);

สิ่งนี้จะเรียกใช้ตัวจัดการของคุณ (ฟังก์ชันหลักที่จะถูกขัดจังหวะ) เป็นเวลา 10 วินาทีจากนั้นจะยกเลิก (เช่นขัดจังหวะ) งานนั้น ๆ


13
ความคิดที่น่าสนใจ แต่ถ้างานเสร็จก่อนหมดเวลา (ซึ่งปกติจะทำ)? ฉันไม่อยากมีงานล้างข้อมูลมากมายรอให้ทำงานเพียงเพื่อพบว่างานที่ได้รับมอบหมายเสร็จสิ้นแล้ว จำเป็นต้องมีเธรดอื่นที่คอยตรวจสอบฟิวเจอร์สเมื่อเสร็จสิ้นเพื่อลบงานการล้างข้อมูล
Edward Dale

4
ตัวดำเนินการจะกำหนดการยกเลิกเพียงครั้งเดียว หากงานเสร็จสิ้นแล้วการยกเลิกจะไม่ทำงานและงานจะดำเนินต่อไปไม่เปลี่ยนแปลง จำเป็นต้องมีเธรดเพิ่มเติมเพียงชุดเดียวเพื่อยกเลิกงานและหนึ่งเธรดเพื่อรัน คุณสามารถมีผู้ดำเนินการสองคนคนหนึ่งส่งงานหลักของคุณและอีกคนหนึ่งเพื่อยกเลิก
John Vint

3
นั่นเป็นความจริง แต่จะเกิดอะไรขึ้นถ้าการหมดเวลาคือ 5 ชั่วโมงและในเวลานั้นงาน 10k จะถูกดำเนินการ ฉันต้องการหลีกเลี่ยงการให้ no-op เหล่านี้แฝงตัวอยู่โดยใช้หน่วยความจำและทำให้เกิดการสลับบริบท
Edward Dale

1
@Scompt ไม่จำเป็น จะมีการเรียกใช้ future.cancel () ถึง 10,000 รายการอย่างไรก็ตามหากอนาคตเสร็จสิ้นการยกเลิกจะทำให้เส้นทางออกไปอย่างรวดเร็วและไม่ทำงานที่ไม่จำเป็น หากคุณไม่ต้องการยกเลิกการเรียกร้องเพิ่มเติม 10k การดำเนินการนี้อาจไม่ได้ผล แต่จำนวนงานที่ทำเมื่องานเสร็จสมบูรณ์นั้นน้อยมาก
John Vint

6
@ จอห์นดับเบิลยู: ฉันเพิ่งตระหนักถึงปัญหาอื่นในการใช้งานของคุณ ฉันต้องการการหมดเวลาเพื่อเริ่มต้นเมื่องานเริ่มดำเนินการตามที่ฉันแสดงความคิดเห็นก่อนหน้านี้ ฉันคิดว่าวิธีเดียวที่จะทำได้คือใช้beforeExecuteเบ็ด
Edward Dale

6

น่าเสียดายที่การแก้ปัญหามีข้อบกพร่อง นอกจากนี้ยังมีข้อผิดพลาดประเภทScheduledThreadPoolExecutorหนึ่งที่รายงานในคำถามนี้ : การยกเลิกงานที่ส่งไม่ได้ปล่อยทรัพยากรหน่วยความจำที่เกี่ยวข้องกับงานอย่างเต็มที่ ทรัพยากรจะถูกปล่อยเมื่องานหมดอายุเท่านั้น

หากคุณสร้างTimeoutThreadPoolExecutorด้วยเวลาหมดอายุที่ค่อนข้างนาน (การใช้งานทั่วไป) และส่งงานเร็วพอคุณจะต้องเติมหน่วยความจำ - แม้ว่างานจะเสร็จสมบูรณ์แล้วก็ตาม

คุณสามารถเห็นปัญหาได้จากโปรแกรมทดสอบ (หยาบคายมาก) ต่อไปนี้:

public static void main(String[] args) throws InterruptedException {
    ExecutorService service = new TimeoutThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, 
            new LinkedBlockingQueue<Runnable>(), 10, TimeUnit.MINUTES);
    //ExecutorService service = Executors.newFixedThreadPool(1);
    try {
        final AtomicInteger counter = new AtomicInteger();
        for (long i = 0; i < 10000000; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    counter.incrementAndGet();
                }
            });
            if (i % 10000 == 0) {
                System.out.println(i + "/" + counter.get());
                while (i > counter.get()) {
                    Thread.sleep(10);
                }
            }
        }
    } finally {
        service.shutdown();
    }
}

โปรแกรมจะทำให้หน่วยความจำที่มีอยู่หมดลงแม้ว่าจะรอให้การสร้างRunnableเสร็จสมบูรณ์

ฉันคิดเกี่ยวกับเรื่องนี้มาระยะหนึ่งแล้ว แต่น่าเสียดายที่ฉันไม่สามารถหาทางออกที่ดีได้

แก้ไข: ฉันพบว่าปัญหานี้ถูกรายงานว่าเป็นข้อผิดพลาด JDK 6602600และดูเหมือนว่าจะได้รับการแก้ไขเมื่อเร็ว ๆ นี้


4

ตัดงานใน FutureTask และคุณสามารถระบุการหมดเวลาสำหรับ FutureTask ดูตัวอย่างในคำตอบของฉันสำหรับคำถามนี้

การหมดเวลากระบวนการดั้งเดิมของ java


1
ฉันรู้ว่ามีสองวิธีในการดำเนินการนี้โดยใช้java.util.concurrentชั้นเรียน แต่ฉันกำลังมองหาExecutorServiceการนำไปใช้
Edward Dale

1
หากคุณกำลังบอกว่าคุณต้องการให้ ExecutorService ของคุณซ่อนความจริงที่ว่าการหมดเวลาถูกเพิ่มจากโค้ดไคลเอนต์คุณสามารถใช้ ExecutorService ของคุณเองซึ่งจะรวมทุกรายการที่รันได้ส่งมอบให้กับ FutureTask ก่อนที่จะดำเนินการ
erikprice

2

หลังจากใช้เวลาในการสำรวจเป็นเวลานาน
ในที่สุดฉันก็ใช้invokeAllวิธีExecutorServiceการแก้ปัญหานี้
ซึ่งจะขัดขวางงานอย่างเคร่งครัดในขณะที่งานกำลังทำงานอยู่
นี่คือตัวอย่าง

ExecutorService executorService = Executors.newCachedThreadPool();

try {
    List<Callable<Object>> callables = new ArrayList<>();
    // Add your long time task (callable)
    callables.add(new VaryLongTimeTask());
    // Assign tasks for specific execution timeout (e.g. 2 sec)
    List<Future<Object>> futures = executorService.invokeAll(callables, 2000, TimeUnit.MILLISECONDS);
    for (Future<Object> future : futures) {
        // Getting result
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

executorService.shutdown();

โปรคือคุณสามารถยื่นListenableFutureพร้อมกันExecutorServiceได้ด้วย
เปลี่ยนโค้ดบรรทัดแรกเล็กน้อย

ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

ListeningExecutorServiceเป็นคุณสมบัติการฟังของExecutorServiceที่โครงการ google guava ( com.google.guava ))


2
invokeAllขอบคุณสำหรับการชี้ให้เห็น ที่ได้ผลดีมาก คำเตือนสำหรับทุกคนที่คิดจะใช้สิ่งนี้แม้ว่าจะinvokeAllส่งคืนรายการFutureวัตถุ แต่ดูเหมือนว่าจะเป็นการดำเนินการปิดกั้น
mxro

1

วิธีการเกี่ยวกับการใช้ExecutorService.shutDownNow()วิธีการที่อธิบายไว้ในhttp://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html ? ดูเหมือนจะเป็นทางออกที่ง่ายที่สุด


8
เพราะมันจะหยุดทุกงานที่กำหนดและไม่ได้เป็นงานที่เฉพาะเจาะจงตามที่ได้รับการร้องขอจากคำถาม
มิเกล

1

ดูเหมือนว่าปัญหาไม่ได้อยู่ในข้อผิดพลาด JDK 6602600 (แก้ไขเมื่อ 2010-05-22) แต่มีการเรียกการนอนหลับที่ไม่ถูกต้อง (10) ในวงกลม นอกจากนี้โปรดทราบว่าเธรดหลักต้องให้โอกาสโดยตรงกับเธรดอื่น ๆ เพื่อให้บรรลุภารกิจของพวกเขาโดยเรียกใช้ SLEEP (0) ในทุก ๆ สาขาของวงนอก ฉันคิดว่าจะดีกว่าถ้าใช้ Thread.yield () แทน Thread.sleep (0)

ผลลัพธ์ที่แก้ไขส่วนของรหัสปัญหาก่อนหน้าเป็นดังนี้:

.......................
........................
Thread.yield();         

if (i % 1000== 0) {
System.out.println(i + "/" + counter.get()+ "/"+service.toString());
}

//                
//                while (i > counter.get()) {
//                    Thread.sleep(10);
//                } 

ทำงานได้อย่างถูกต้องกับจำนวนของเคาน์เตอร์ด้านนอกที่มีการทดสอบมากถึง 150,000,000 วงกลม


1

การใช้ John W answer ฉันสร้างการใช้งานที่เริ่มการหมดเวลาอย่างถูกต้องเมื่องานเริ่มดำเนินการ ฉันเขียนแบบทดสอบหน่วยด้วยซ้ำ :)

อย่างไรก็ตามมันไม่เหมาะกับความต้องการของฉันเนื่องจากการดำเนินการ IO บางอย่างไม่ขัดจังหวะเมื่อFuture.cancel()ถูกเรียก (เช่นเมื่อThread.interrupt()ถูกเรียก) ตัวอย่างบางส่วนของการดำเนินการ IO ที่อาจไม่ถูกขัดจังหวะเมื่อThread.interrupt()ถูกเรียกคือSocket.connectและSocket.read(และฉันสงสัยว่าการดำเนินการ IO ส่วนใหญ่ถูกนำมาใช้java.io) การดำเนินการ IO ทั้งหมดในjava.nioควรถูกขัดจังหวะเมื่อThread.interrupt()ถูกเรียก ยกตัวอย่างเช่นว่าเป็นกรณีสำหรับและSocketChannel.openSocketChannel.read

อย่างไรก็ตามถ้าใครสนใจฉันได้สร้างส่วนสำคัญสำหรับตัวดำเนินการเธรดพูลที่อนุญาตให้งานหมดเวลา (หากพวกเขาใช้การดำเนินการขัดจังหวะ ... ): https://gist.github.com/amanteaux/64c54a913c1ae34ad7b86db109cbc0bf


รหัสที่น่าสนใจฉันดึงมันเข้าไปในระบบของฉันและอยากรู้ว่าคุณมีตัวอย่างบ้างไหมว่าการทำงานของ IO แบบไหนที่จะไม่ขัดจังหวะฉันจะได้ดูว่ามันจะส่งผลกระทบต่อระบบของฉันหรือไม่ ขอบคุณ!
Duncan Krebs

@DuncanKrebs ฉันให้รายละเอียดคำตอบของฉันด้วยตัวอย่างของ IO ที่ไม่ขัดจังหวะ: Socket.connectและSocket.read
amanteaux

myThread.interrupted()ไม่ใช่วิธีการที่ถูกต้องในการขัดจังหวะเนื่องจากจะล้างแฟล็กการขัดจังหวะ ใช้myThread.interrupt()แทนและควรใช้กับซ็อกเก็ต
DanielCuadra

@DanielCuadra: ขอบคุณดูเหมือนว่าฉันพิมพ์ผิดเพราะThread.interrupted()ไม่สามารถขัดจังหวะเธรดได้ อย่างไรก็ตามThread.interrupt()ไม่ขัดจังหวะjava.ioการดำเนินการทำงานเฉพาะกับjava.nioการดำเนินงานเท่านั้น
amanteaux

ฉันใช้มาinterrupt()หลายปีแล้วและมันขัดจังหวะการทำงานของ java.io อยู่เสมอ (รวมถึงวิธีการบล็อกอื่น ๆ เช่นการพักเธรดการเชื่อมต่อ jdbc การบล็อกคิว ฯลฯ ) บางทีคุณอาจพบคลาส buggy หรือ JVM ที่มีข้อบกพร่อง
DanielCuadra

0

แนวคิดทางเลือกนี้มีอะไรบ้าง:

  • สองคนมีผู้ปฏิบัติการสองคน:
    • หนึ่งสำหรับ:
      • ส่งงานโดยไม่สนใจว่าจะหมดเวลาของงาน
      • การเพิ่มผลลัพธ์ในอนาคตและเวลาที่ควรสิ้นสุดลงในโครงสร้างภายใน
    • หนึ่งสำหรับการดำเนินการงานภายในซึ่งกำลังตรวจสอบโครงสร้างภายในว่างานบางอย่างหมดเวลาหรือไม่และต้องยกเลิกหรือไม่

ตัวอย่างขนาดเล็กอยู่ที่นี่:

public class AlternativeExecutorService 
{

private final CopyOnWriteArrayList<ListenableFutureTask> futureQueue       = new CopyOnWriteArrayList();
private final ScheduledThreadPoolExecutor                scheduledExecutor = new ScheduledThreadPoolExecutor(1); // used for internal cleaning job
private final ListeningExecutorService                   threadExecutor    = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); // used for
private ScheduledFuture scheduledFuture;
private static final long INTERNAL_JOB_CLEANUP_FREQUENCY = 1000L;

public AlternativeExecutorService()
{
    scheduledFuture = scheduledExecutor.scheduleAtFixedRate(new TimeoutManagerJob(), 0, INTERNAL_JOB_CLEANUP_FREQUENCY, TimeUnit.MILLISECONDS);
}

public void pushTask(OwnTask task)
{
    ListenableFuture<Void> future = threadExecutor.submit(task);  // -> create your Callable
    futureQueue.add(new ListenableFutureTask(future, task, getCurrentMillisecondsTime())); // -> store the time when the task should end
}

public void shutdownInternalScheduledExecutor()
{
    scheduledFuture.cancel(true);
    scheduledExecutor.shutdownNow();
}

long getCurrentMillisecondsTime()
{
    return Calendar.getInstance().get(Calendar.MILLISECOND);
}

class ListenableFutureTask
{
    private final ListenableFuture<Void> future;
    private final OwnTask                task;
    private final long                   milliSecEndTime;

    private ListenableFutureTask(ListenableFuture<Void> future, OwnTask task, long milliSecStartTime)
    {
        this.future = future;
        this.task = task;
        this.milliSecEndTime = milliSecStartTime + task.getTimeUnit().convert(task.getTimeoutDuration(), TimeUnit.MILLISECONDS);
    }

    ListenableFuture<Void> getFuture()
    {
        return future;
    }

    OwnTask getTask()
    {
        return task;
    }

    long getMilliSecEndTime()
    {
        return milliSecEndTime;
    }
}

class TimeoutManagerJob implements Runnable
{
    CopyOnWriteArrayList<ListenableFutureTask> getCopyOnWriteArrayList()
    {
        return futureQueue;
    }

    @Override
    public void run()
    {
        long currentMileSecValue = getCurrentMillisecondsTime();
        for (ListenableFutureTask futureTask : futureQueue)
        {
            consumeFuture(futureTask, currentMileSecValue);
        }
    }

    private void consumeFuture(ListenableFutureTask futureTask, long currentMileSecValue)
    {
        ListenableFuture<Void> future = futureTask.getFuture();
        boolean isTimeout = futureTask.getMilliSecEndTime() >= currentMileSecValue;
        if (isTimeout)
        {
            if (!future.isDone())
            {
                future.cancel(true);
            }
            futureQueue.remove(futureTask);
        }
    }
}

class OwnTask implements Callable<Void>
{
    private long     timeoutDuration;
    private TimeUnit timeUnit;

    OwnTask(long timeoutDuration, TimeUnit timeUnit)
    {
        this.timeoutDuration = timeoutDuration;
        this.timeUnit = timeUnit;
    }

    @Override
    public Void call() throws Exception
    {
        // do logic
        return null;
    }

    public long getTimeoutDuration()
    {
        return timeoutDuration;
    }

    public TimeUnit getTimeUnit()
    {
        return timeUnit;
    }
}
}

0

ตรวจสอบว่าสิ่งนี้เหมาะกับคุณหรือไม่

    public <T,S,K,V> ResponseObject<Collection<ResponseObject<T>>> runOnScheduler(ThreadPoolExecutor threadPoolExecutor,
      int parallelismLevel, TimeUnit timeUnit, int timeToCompleteEachTask, Collection<S> collection,
      Map<K,V> context, Task<T,S,K,V> someTask){
    if(threadPoolExecutor==null){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("threadPoolExecutor can not be null").build();
    }
    if(someTask==null){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("Task can not be null").build();
    }
    if(CollectionUtils.isEmpty(collection)){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("input collection can not be empty").build();
    }

    LinkedBlockingQueue<Callable<T>> callableLinkedBlockingQueue = new LinkedBlockingQueue<>(collection.size());
    collection.forEach(value -> {
      callableLinkedBlockingQueue.offer(()->someTask.perform(value,context)); //pass some values in callable. which can be anything.
    });
    LinkedBlockingQueue<Future<T>> futures = new LinkedBlockingQueue<>();

    int count = 0;

    while(count<parallelismLevel && count < callableLinkedBlockingQueue.size()){
      Future<T> f = threadPoolExecutor.submit(callableLinkedBlockingQueue.poll());
      futures.offer(f);
      count++;
    }

    Collection<ResponseObject<T>> responseCollection = new ArrayList<>();

    while(futures.size()>0){
      Future<T> future = futures.poll();
      ResponseObject<T> responseObject = null;
        try {
          T response = future.get(timeToCompleteEachTask, timeUnit);
          responseObject = ResponseObject.<T>builder().data(response).build();
        } catch (InterruptedException e) {
          future.cancel(true);
        } catch (ExecutionException e) {
          future.cancel(true);
        } catch (TimeoutException e) {
          future.cancel(true);
        } finally {
          if (Objects.nonNull(responseObject)) {
            responseCollection.add(responseObject);
          }
          futures.remove(future);//remove this
          Callable<T> callable = getRemainingCallables(callableLinkedBlockingQueue);
          if(null!=callable){
            Future<T> f = threadPoolExecutor.submit(callable);
            futures.add(f);
          }
        }

    }
    return ResponseObject.<Collection<ResponseObject<T>>>builder().data(responseCollection).build();
  }

  private <T> Callable<T> getRemainingCallables(LinkedBlockingQueue<Callable<T>> callableLinkedBlockingQueue){
    if(callableLinkedBlockingQueue.size()>0){
      return callableLinkedBlockingQueue.poll();
    }
    return null;
  }

คุณสามารถ จำกัด การไม่ใช้เธรดจากตัวกำหนดตารางเวลาและกำหนดระยะหมดเวลาของงานได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.