/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * 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 org.fusesource.hawtdispatch.internal.pool; import org.fusesource.hawtdispatch.DispatchPriority; import org.fusesource.hawtdispatch.Task; import org.fusesource.hawtdispatch.internal.*; import java.io.IOException; import java.util.concurrent.ConcurrentLinkedQueue; import static java.lang.String.format; /** */ public class SimplePool implements WorkerPool { final ConcurrentLinkedQueue<Task> tasks = new ConcurrentLinkedQueue<Task>(); final GlobalDispatchQueue globalQueue; final String name; final int priority; final SimpleThread[] threads; volatile boolean shutdown = false; final ThreadGroup group; public SimplePool(GlobalDispatchQueue globalQueue, int parallelism, DispatchPriority priority) { this.globalQueue = globalQueue; this.name = globalQueue.dispatcher.getLabel()+"-"+priority; this.group = new HawtThreadGroup(globalQueue.dispatcher, name); this.priority = priority(priority); this.threads = new SimpleThread[parallelism]; } static private int priority(DispatchPriority priority) { switch(priority) { case HIGH: return Thread.MAX_PRIORITY; case DEFAULT: return Thread.NORM_PRIORITY; case LOW: return Thread.MIN_PRIORITY; } return 0; } public void start() { shutdown = false; for (int i=0; i < threads.length; i++) { threads[i] = createWorker(i); threads[i].start(); } } private SimpleThread createWorker(int index) { SimpleThread w; try { w = new SimpleThread(this); } catch (Exception e) { throw new RuntimeException(e); } w.setDaemon(true); w.setPriority(priority); w.setName(name + "-" + (index+1)); return w; } public WorkerThread[] getThreads() { return threads; } public void shutdown() { try { // wait for the queue to get drained.. while( !tasks.isEmpty() ) { Thread.sleep(50); } // now shutdown the threads. shutdown = true; for (int i=0; i < threads.length; i++) { threads[i].unpark(); } for (int i=0; i < threads.length; i++) { threads[i].join(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public void execute(Task runnable) { WorkerThread current = WorkerThread.currentWorkerThread(); tasks.add(runnable); // If there are idle threads.. wake one up to process the runnable. for (int i=0; i < threads.length; i++) { // no need to wakeup the current thread. if( threads[i]==current ) { continue; } // A sleeping thread will be waiting in his selector.. NioManager nio = threads[i].getNioManager(); if( nio.wakeupIfSelecting() ) { break; } } } public void park(SimpleThread thread) { try { debug("parking thread: %s", thread.getName()); thread.getNioManager().select(-1); debug("unparking thread: %s", thread.getName()); } catch (IOException e) { throw new RuntimeException(e); } } public static final boolean DEBUG = false; protected void debug(String str, Object... args) { if (DEBUG) { System.out.println(format("[DEBUG] SimplePool %0#10x: ", System.identityHashCode(this))+format(str, args)); } } protected void debug(Throwable thrown, String str, Object... args) { if (DEBUG) { if (str != null) { debug(str, args); } if (thrown != null) { thrown.printStackTrace(); } } } }