Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在任务之间安排最长/最短持续时间的任务_Java_Multithreading_Timer_Scheduledexecutorservice - Fatal编程技术网

Java 在任务之间安排最长/最短持续时间的任务

Java 在任务之间安排最长/最短持续时间的任务,java,multithreading,timer,scheduledexecutorservice,Java,Multithreading,Timer,Scheduledexecutorservice,正在刷新数据库中的记录。我们要么得到一个明确的刷新通知,要么每60秒轮询一次。每秒刷新次数不超过一次 如果一个请求进入,如果一秒钟内没有刷新,它应该排队立即刷新。否则,它应该在上次刷新结束后安排刷新1秒,除非已经为该时间或更早时间安排了此类任务 在没有显式刷新的一分钟后,计时器应启动并刷新,以防未发送通知 可能会有大量通知传入(每秒数百个) 刷新可以通过单独的单个线程完成 什么是优雅的设计方式 以下是我所拥有的,但这可能会导致太多的请求: private NotificationCenter()

正在刷新数据库中的记录。我们要么得到一个明确的刷新通知,要么每60秒轮询一次。每秒刷新次数不超过一次

如果一个请求进入,如果一秒钟内没有刷新,它应该排队立即刷新。否则,它应该在上次刷新结束后安排刷新1秒,除非已经为该时间或更早时间安排了此类任务

在没有显式刷新的一分钟后,计时器应启动并刷新,以防未发送通知

可能会有大量通知传入(每秒数百个)

刷新可以通过单独的单个线程完成

什么是优雅的设计方式

以下是我所拥有的,但这可能会导致太多的请求:

private NotificationCenter() {
    recordFetchService = Executors.newSingleThreadScheduledExecutor();
    recordFetchService.scheduleWithFixedDelay(refreshCommand, minTimeBetweenRefresh, maxTimeBetweenRefresh, TimeUnit.MILLISECONDS);
}

private void queueRefresh() {
    // explicit refresh requested. Schedule a refreshCommand to fire immediately, unless that would break our contract
    if (!pending.isDone() && pending.getDelay(TimeUnit.MILLISECONDS) < minTimeBetweenRefresh) {
        // a refresh is already scheduled
    } else {
        pending = recordFetchService.schedule(refreshCommand, 0L, TimeUnit.MILLISECONDS);
    }
}
私人通知中心(){
recordFetchService=Executors.newSingleThreadScheduledExecutor();
recordFetchService.scheduleWithFixedDelay(刷新命令,MintTimeBetweenRefresh,maxTimeBetweenRefresh,时间单位为毫秒);
}
私有无效队列刷新(){
//请求显式刷新。计划立即启动refreshCommand,除非这会破坏我们的合同
如果(!pending.isDone()&&pending.getDelay(TimeUnit.millides)
在“每秒数百次通知”的情况下,
原子布尔值
可以将状态从“无所事事”切换到“准备做某事”,反之亦然。将“准备做某事”状态与一个
信号量相结合,您可以选择确定“准备做某事”发生的确切时刻

下面是一个(可运行的)示例实现/设计,它结合了
原子布尔
信号量
,在使用通知时定期刷新数据。这可能不是最优雅的方式,但我确实认为它以一种相对简单的方式实现了目标

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

public class RefreshTask {

    private static final long MIN_WAIT_MS = 100L;
    private static final long MAX_WAIT_MS = 1000L;

    private ScheduledExecutorService scheduler;
    private ExecutorService executor;
    private volatile boolean stopping; 

    private final Semaphore refreshLock = new Semaphore(0);
    private final AtomicBoolean refreshing = new AtomicBoolean();
    private volatile long lastRefresh;

    public void start() {

        stopping = false;
        refreshing.set(true);
        lastRefresh = System.currentTimeMillis();
        executor = Executors.newSingleThreadExecutor();
        executor.execute(new RefreshLoop());
        scheduler = Executors.newSingleThreadScheduledExecutor();
    }

    public void stop() {

        stopping = true;
        if (executor != null) {
            refreshLock.release();
            scheduler.shutdownNow();
            executor.shutdownNow();
        }
    }

    /** Trigger a (scheduled) refresh of data. */
    public void refresh() {

        if (refreshing.compareAndSet(false, true)) {
            final long dataAge = System.currentTimeMillis() - lastRefresh;
            if (dataAge >= MIN_WAIT_MS) {
                refreshLock.release();
                // println("Refresh lock released.");
            } else {
                long waitTime = MIN_WAIT_MS - dataAge;
                scheduler.schedule(new RefreshReleaser(), waitTime, TimeUnit.MILLISECONDS);
                println("Refresh scheduled in " + waitTime + " ms.");
            }
        } else {
            // println("Refresh already triggered.");
        }
    }

    protected void refreshData() {

        // Refresh data from database
        println("DATA refresh");
    }

    class RefreshLoop implements Runnable {

        @Override
        public void run() {

            while (!stopping) {
                try {
                    refreshData();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                lastRefresh = System.currentTimeMillis();
                refreshing.set(false);
                try {
                    if (!refreshLock.tryAcquire(MAX_WAIT_MS, TimeUnit.MILLISECONDS)) {
                        if (!refreshing.compareAndSet(false, true)) {
                            // Unlikely state, but can happen if "dataAge" in the refresh-method is around MAX_WAIT_MS.
                            // Resolve the race-condition by removing the extra permit.
                            if (refreshLock.tryAcquire()) {
                                println("Refresh lock race-condition detected, removed additional permit.");
                            } else {
                                println("Refresh lock race-condition detected, but no additional permit found.");
                            }
                        }
                        println("Refreshing after max waiting time.");
                    } // else refreshing already set to true
                } catch (InterruptedException ie) {
                    if (!stopping) {
                        ie.printStackTrace();
                    }
                }
            }
            println("Refresh loop stopped.");
        }
    }

    class RefreshReleaser implements Runnable {

        @Override
        public void run() {

            if (refreshing.get()) {
                refreshLock.release();
                println("Scheduled refresh lock release.");
            } else {
                println("Programming error, scheduled refresh lock release can only be done in refreshing state.");
            }
        }
    }

    /* *** some testing *** */

    public static void main(String[] args) {

        RefreshTask rt = new RefreshTask();
        try {
            println("Starting");
            rt.start();
            Thread.sleep(2 * MIN_WAIT_MS);
            println("Triggering refresh");
            rt.refresh();
            Thread.sleep(MAX_WAIT_MS + (MIN_WAIT_MS / 2));
            println("Triggering refresh 2");
            rt.refresh();
            Thread.sleep(MIN_WAIT_MS);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rt.stop();
        }
    }

    public static final long startTime = System.currentTimeMillis();

    public static void println(String msg) {
        println(System.currentTimeMillis() - startTime, msg);
    }

    public static void println(long tstamp, String msg) {
        System.out.println(String.format("%05d ", tstamp) + msg);
    }

}