All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.netty.util.VirtualExecutorService Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you 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 org.jboss.netty.util;

import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;

import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;


/**
 * A delegating {@link ExecutorService} with its own termination management.
 * 

* {@link VirtualExecutorService} is used when you want to inject an * {@link ExecutorService} but you do not want to allow the explicit termination * of threads on shutdown request. It is particularly useful when the * {@link ExecutorService} to inject is shared by different components and * the life cycle of the components depend on the termination of the injected * {@link ExecutorService}. * *

 * ExecutorService globalExecutor = ...;
 * ExecutorService virtualExecutor = new {@link VirtualExecutorService}(globalExecutor);
 *
 * {@link ChannelFactory} factory =
 *         new {@link NioServerSocketChannelFactory}(virtualExecutor, virtualExecutor);
 * ...
 *
 * // ChannelFactory.releaseExternalResources() shuts down the executor and
 * // interrupts the I/O threads to terminate all I/O tasks and to release all
 * // resources acquired by ChannelFactory.
 * factory.releaseExternalResources();
 *
 * // Note that globalExecutor is not shut down because VirtualExecutorService
 * // implements its own termination management. All threads which were acquired
 * // by ChannelFactory via VirtualExecutorService are returned to the pool.
 * assert !globalExecutor.isShutdown();
 * 
* *

The differences from an ordinary {@link ExecutorService}

* * A shutdown request ({@link #shutdown()} or {@link #shutdownNow()}) does not * shut down its parent {@link Executor} but simply sets its internal flag to * reject further execution request. *

* {@link #shutdownNow()} interrupts only the thread which is executing the * task executed via {@link VirtualExecutorService}. *

* {@link #awaitTermination(long, TimeUnit)} does not wait for real thread * termination but wait until {@link VirtualExecutorService} is shut down and * its active tasks are finished and the threads are returned to the parent * {@link Executor}. * @apiviz.landmark */ public class VirtualExecutorService extends AbstractExecutorService { private final Executor e; private final ExecutorService s; final Object startStopLock = new Object(); volatile boolean shutdown; final Set activeThreads = new MapBackedSet(new IdentityHashMap()); /** * Creates a new instance with the specified parent {@link Executor}. */ public VirtualExecutorService(Executor parent) { if (parent == null) { throw new NullPointerException("parent"); } if (parent instanceof ExecutorService) { e = null; s = (ExecutorService) parent; } else { e = parent; s = null; } } public boolean isShutdown() { synchronized (startStopLock) { return shutdown; } } public boolean isTerminated() { synchronized (startStopLock) { return shutdown && activeThreads.isEmpty(); } } public void shutdown() { synchronized (startStopLock) { if (shutdown) { return; } shutdown = true; } } public List shutdownNow() { synchronized (startStopLock) { if (!isTerminated()) { shutdown(); for (Thread t: activeThreads) { t.interrupt(); } } } return Collections.emptyList(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { synchronized (startStopLock) { if (!isTerminated()) { startStopLock.wait(TimeUnit.MILLISECONDS.convert(timeout, unit)); } return isTerminated(); } } public void execute(Runnable command) { if (command == null) { throw new NullPointerException("command"); } if (shutdown) { throw new RejectedExecutionException(); } if (s != null) { s.execute(new ChildExecutorRunnable(command)); } else { e.execute(new ChildExecutorRunnable(command)); } } private class ChildExecutorRunnable implements Runnable { private final Runnable runnable; ChildExecutorRunnable(Runnable runnable) { this.runnable = runnable; } public void run() { Thread thread = Thread.currentThread(); synchronized (startStopLock) { activeThreads.add(thread); } try { runnable.run(); } finally { synchronized (startStopLock) { boolean removed = activeThreads.remove(thread); assert removed; if (isTerminated()) { startStopLock.notifyAll(); } } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy