/* * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.util.concurrency; import com.intellij.openapi.diagnostic.Logger; import java.util.concurrent.DelayQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; /** * This class implements the global delayed queue which is used by * {@link AppScheduledExecutorService} and {@link BoundedScheduledExecutorService}. * It starts the background thread which polls the queue for tasks ready to run and sends them to the appropriate executor. * The {@link #shutdown()} must be called before disposal. */ class AppDelayQueue extends DelayQueue<SchedulingWrapper.MyScheduledFutureTask> { private static final Logger LOG = Logger.getInstance("#com.intellij.util.concurrency.AppDelayQueue"); private final Thread scheduledToPooledTransferer; private final AtomicBoolean shutdown = new AtomicBoolean(); AppDelayQueue() { /* this thread takes the ready-to-execute scheduled tasks off the queue and passes them for immediate execution to {@link SchedulingWrapper#backendExecutorService} */ scheduledToPooledTransferer = new Thread(new Runnable() { @Override public void run() { while (!shutdown.get()) { try { final SchedulingWrapper.MyScheduledFutureTask task = take(); if (LOG.isTraceEnabled()) { LOG.trace("Took "+BoundedTaskExecutor.info(task)); } if (!task.isDone()) { // can be cancelled already ExecutorService backendExecutorService = task.getBackendExecutorService(); try { backendExecutorService.execute(task); } catch (Throwable e) { try { LOG.error("Error executing "+task+" in "+backendExecutorService, e); } catch (Throwable ignored) { // do not let it stop the thread } } } } catch (InterruptedException e) { if (!shutdown.get()) { LOG.error(e); } } } LOG.debug("scheduledToPooledTransferer Stopped"); } }, "Periodic tasks thread"); scheduledToPooledTransferer.setDaemon(true); // mark as daemon to not prevent JVM to exit (needed for Kotlin CLI compiler) scheduledToPooledTransferer.start(); } void shutdown() { if (shutdown.getAndSet(true)) { throw new IllegalStateException("Already shutdown"); } scheduledToPooledTransferer.interrupt(); try { scheduledToPooledTransferer.join(); } catch (Exception e) { throw new RuntimeException(e); } } Thread getThread() { return scheduledToPooledTransferer; } }