NewSingleThreadScheduledExecutor: produce a ScheduledExecutorService object, the object of the thread pool size is 1, if more than one task, the task will be executed according to the order.

1. Inheritance structure

The constructor

Contains a timed service

 

public static ScheduledExecutorService newSingleThreadScheduledExecutor(a) {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}

static class DelegatedScheduledExecutorService
        extends DelegatedExecutorService
        implements ScheduledExecutorService {
    private final ScheduledExecutorService e;
    DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
        super(executor);
        e = executor;
    }
Copy the code

2. How to ensure only one thread

This method is called on timed execution as follows, noting the comments in the call order from top to bottom

publicScheduledFuture<? > scheduleWithFixedDelay(Runnable command,long initialDelay,
                                                 long delay,
                                                 TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    if (delay <= 0)
        throw new IllegalArgumentException();
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(-delay));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    // Delay execution
    delayedExecute(t);
    return t;
}
private void delayedExecute(RunnableScheduledFuture
        task) {
    if (isShutdown())
        reject(task);
    else {
        // Join the task queue
        super.getQueue().add(task);
        if(isShutdown() && ! canRunInCurrentRunState(task.isPeriodic()) && remove(task)) task.cancel(false);
        else
            // Ensure executionensurePrestart(); }}// If the number of workers is smaller than corePoolSize, create a new thread
void ensurePrestart(a) {
    int wc = workerCountOf(ctl.get());
    if (wc < corePoolSize)
        addWorker(null.true);
    else if (wc == 0)
        addWorker(null.false);
}
Copy the code

3. How to ensure that the time can be executed regularly

publicScheduledFuture<? > schedule(Runnable command,long delay,
                                   TimeUnit unit) {
    if (command == null || unit == null)
        throw newNullPointerException(); RunnableScheduledFuture<? > t = decorateTask(command,new ScheduledFutureTask<Void>(command, null,
                                      triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}
Copy the code

Each time the task is executed, the time of the next execution is put into the task

private long triggerTime(long delay, TimeUnit unit) {
    return triggerTime(unit.toNanos((delay < 0)?0 : delay));
}

/** * Returns the trigger time of a delayed action. */
long triggerTime(long delay) {
    return now() +
        ((delay < (Long.MAX_VALUE >> 1))? delay : overflowFree(delay)); }Copy the code

 

FutureTask timing is done through locksupport.parknanos (this, nanos); LockSupport.park(this);

private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }

        int s = state;
        if (s > COMPLETING) {
            if(q ! =null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        else if (q == null)
            q = new WaitNode();
        else if(! queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
        else if (timed) {
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q);
                return state;
            }
            // Notice here
            LockSupport.parkNanos(this, nanos);
        }
        else // Notice here
            LockSupport.park(this); }}Copy the code

 

Summary: Executors are FutureTasks that are generated by putting tasks in queues. Then the generated tasks are sorted in the queue, and the latest tasks that need to start are checked. If not, the thread is blocked until the next departure time.

Note: newSingleThreadScheduledExecutor will only have a single thread, no matter how much you submitted the task, these tasks will be executed sequentially, if an exception occurs will cancel the following task, the thread pool will not shut down, pay attention to catch exceptions

4, the use of

ScheduledExecutorService single = Executors.newSingleThreadScheduledExecutor();
Runnable runnable1 = () -> {
    try {
        Thread.sleep(4000);
        System.out.println("11111111111111");

    } catch(InterruptedException e) { e.printStackTrace(); }}; Runnable runnable2 = () -> {try {
        Thread.sleep(4000);
        System.out.println("222");

    } catch(InterruptedException e) { e.printStackTrace(); }}; single.scheduleWithFixedDelay(runnable1,0.1, TimeUnit.SECONDS);
single.scheduleWithFixedDelay(runnable2,0.2, TimeUnit.SECONDS);
Copy the code
11111111111111
222
11111111111111
222
11111111111111
Copy the code

Be careful to turn off thread pools in your project

actionService = Executors.newSingleThreadScheduledExecutor();
        actionService.scheduleWithFixedDelay(() -> {
            try {
                Thread.currentThread().setName("robotActionService");
                Integer robotId = robotQueue.poll();
                if (robotId == null) {
                    // Close the thread pool
                    actionService.shutdown();
                } else {
                    int aiLv = robots.get(robotId);
                    if(actionQueueMap.containsKey(aiLv)) { ActionQueue actionQueue = actionQueueMap.get(aiLv); actionQueue.doAction(robotId); }}}catch (Exception e) {
                // Catch exceptions
                LOG.error("",e); }},1.1, TimeUnit.SECONDS);
Copy the code

Welcome to reprint, I’m coriander, thank you. Welcome to join QQ group: 632603498, learn together