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

com.sun.jmx.remote.opt.util.ThreadService Maven / Gradle / Ivy

/*
 * @(#)file      ThreadService.java
 * @(#)author    Sun Microsystems, Inc.
 * @(#)version   1.9
 * @(#)lastedit  07/03/08
 * @(#)build     @BUILD_TAG_PLACEHOLDER@
 *
 * 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU General
 * Public License Version 2 only ("GPL") or the Common Development and
 * Distribution License("CDDL")(collectively, the "License"). You may not use
 * this file except in compliance with the License. You can obtain a copy of the
 * License at http://opendmk.dev.java.net/legal_notices/licenses.txt or in the 
 * LEGAL_NOTICES folder that accompanied this code. See the License for the 
 * specific language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file found at
 *     http://opendmk.dev.java.net/legal_notices/licenses.txt
 * or in the LEGAL_NOTICES folder that accompanied this code.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.
 * 
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * 
 *       "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding
 * 
 *       "[Contributor] elects to include this software in this distribution
 *        under the [CDDL or GPL Version 2] license."
 * 
 * If you don't indicate a single choice of license, a recipient has the option
 * to distribute your version of this file under either the CDDL or the GPL
 * Version 2, or to extend the choice of license to its licensees as provided
 * above. However, if you add GPL Version 2 code and therefore, elected the
 * GPL Version 2 license, then the option applies only if the new code is made
 * subject to such option by the copyright holder.
 * 
 */ 

package com.sun.jmx.remote.opt.util;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;

public class ThreadService {

    public ThreadService(int min, int max) {
	this(min, max, true);
    }

    public ThreadService(int min, int max, boolean simple) {
	if (min < 0) {
	    throw new IllegalArgumentException("Negative minimal thread number.");
	}

	if (max < min) {
	    throw new IllegalArgumentException("Maximum number less than minimal number.");
	}

	this.min = min;
	this.max = max;
	this.simple = simple;

	defaultPriority = Thread.currentThread().getPriority();
	defaultLoader = getContextClassLoader();

	if (min > 0) {
	    JobExecutor.handoff(new ThreadServiceJob());
	}
    }
 
    public void handoff(Runnable job) {
	isTerminated();

	if (job == null) {
	    throw new IllegalArgumentException("Null job.");
	}

	synchronized(lock) {
	    jobList.add(job);

	    // there are enough idle threads
	    if (jobList.size() <= idle) {
		lock.notify();
		return;
	    }

	    // should ask more threads immidiately
	    if (total < min || total == 0) {
		total++;
		JobExecutor.handoff(new ThreadServiceJob());

		return;
	    }

	    // no more thread can be asked
	    if (total == max) {
		return;
	    }
	}

	// wait a while for working threads become possibly idle
	Thread.yield();

	// see if ask more thread
	synchronized(lock) {
	    if (jobList.size() > idle && total < max) {
		total++;
		JobExecutor.handoff(new ThreadServiceJob());
	    }
	}
    }

    public void terminate() {
	synchronized(lock) {
	    if (terminated) {
		return;
	    }

	    terminated = true;

	    jobList.clear();
	    lock.notifyAll();
	
	    Thread ct = Thread.currentThread();

	    while (threadList.size() > 0) {
		Thread rt = (Thread)threadList.remove(0);
		if (ct != rt) {
		    rt.interrupt();
		}		    
	    }
	}		
    }

//     public static ThreadService getShared() {
// 	return shared;
//     }

// private stuff
    private class ThreadServiceJob implements Runnable {
        public ThreadServiceJob() {
        }

        public void run() {
	    Thread currentThread = Thread.currentThread();

	    synchronized(lock) {
		threadList.add(currentThread);
	    }

	    // init
	    currentThread.setPriority(defaultPriority);
	    currentThread.interrupted();
	    setContextClassLoader(currentThread, defaultLoader);

	    Runnable job = null;

	    while (!terminated) {
		synchronized(lock) {
		    if (jobList.size() == 0) {
			if (total > min) {
			    if (idle == 0) { // keep one with timeout
				idle++;

				// waiting with timeout
				long remainingTime = LEAVING_WAITING_TIME;
				final long startTime = System.currentTimeMillis();

				while(jobList.size() <= 0 && remainingTime > 0) {
				    try {
					lock.wait(remainingTime);
				    } catch (InterruptedException e) {
					// clean the flag, the thread will be reused.
					currentThread.interrupted();

					if (terminated) {
					    return;
					}
				    }

				    remainingTime = LEAVING_WAITING_TIME -
					(System.currentTimeMillis() - startTime);
				}

				idle--;

				if (jobList.size() > 0) {
				    job = (Runnable)jobList.remove(0);
				} else {
				    // still no job, leaving
				    // do here within synchronization
				    total--;
				    threadList.remove(currentThread);

				    break;
				}
			    } else {
				// outside of min and some other threads are idle, leave
				// do here within synchronization
				total--;
				threadList.remove(currentThread);

				break;
			    }
			} else { // staying within min
			    idle++;

			    while(!terminated && jobList.size() <= 0) {
				try {
				    lock.wait();			
				} catch (InterruptedException ire) {
				    // OK
				    // should not happen in this step
				}
			    }
			    
			    idle--;
			    
			    if (terminated) {
				break;
			    }

			    job = (Runnable)jobList.remove(0);
			}
		    } else {
			job = (Runnable)jobList.remove(0);
                    }
		}

		if (terminated) {
		    break;
		}

		try {
		    job.run();
		} catch (Exception e) {
		    if (logger.warningOn()) {
			logger.warning("run", "Got an unexpected exception.", e);
		    }
		} finally {
		    job = null;
		}

		currentThread.interrupted();

		if (!simple) {
		    // re-init
		    currentThread.setPriority(defaultPriority);
		    setContextClassLoader(currentThread, defaultLoader);
		}
	    }

	    // important!!!
	    // This thread will possibly go to another ThreadService,
	    // it is important to remove its interrupted flag (if set)
	    currentThread.interrupted();
	}
    }

    protected void finalize() {
	terminate();
    }

    private void isTerminated() throws IllegalStateException {
	if (terminated) {
	    throw new IllegalStateException("The Thread Service has been terminated.");
	}
    }

    private ClassLoader getContextClassLoader() {
	return (ClassLoader)
	    AccessController.doPrivileged(new PrivilegedAction() {
		    public Object run() {
			return Thread.currentThread().getContextClassLoader();
		    }
	    });
    }

    private void setContextClassLoader(final Thread currentThread,
				       final ClassLoader classloader) {
	AccessController.doPrivileged(new PrivilegedAction() {
		public Object run() {
		    currentThread.setContextClassLoader(classloader);
		    return null;
		}
	});
    }

// private stuff
    private int min;
    private int max;
    private boolean simple;

    private int total = 0;
    private int idle = 0;
    private boolean terminated = false;

    private ArrayList jobList = new ArrayList();
    private ArrayList threadList = new ArrayList();

    private static final ThreadService shared = new ThreadService(0, Integer.MAX_VALUE);

    private int defaultPriority;
    private ClassLoader defaultLoader;
    private int[] lock = new int[0];

    private static final int LEAVING_WAITING_TIME = 1000;

    private static final ClassLogger logger = 
	new ClassLogger("com.sun.jmx.remote.opt.util", 
			"ThreadService");
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy