Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zeroc.IceInternal.ThreadPool Maven / Gradle / Ivy
//
// Copyright (c) ZeroC, Inc. All rights reserved.
//
package com.zeroc.IceInternal;
public final class ThreadPool implements java.util.concurrent.Executor
{
final class ShutdownWorkItem implements ThreadPoolWorkItem
{
@Override
public void execute(ThreadPoolCurrent current)
{
current.ioCompleted();
try
{
_instance.objectAdapterFactory().shutdown();
}
catch(com.zeroc.Ice.CommunicatorDestroyedException ex)
{
}
}
}
static final class FinishedWorkItem implements ThreadPoolWorkItem
{
public
FinishedWorkItem(EventHandler handler, boolean close)
{
_handler = handler;
_close = close;
}
@Override
public void execute(ThreadPoolCurrent current)
{
_handler.finished(current, _close);
}
private final EventHandler _handler;
private final boolean _close;
}
static final class JoinThreadWorkItem implements ThreadPoolWorkItem
{
public
JoinThreadWorkItem(EventHandlerThread thread)
{
_thread = thread;
}
@Override
public void execute(ThreadPoolCurrent current)
{
// No call to ioCompleted, this shouldn't block (and we don't want to cause
// a new thread to be started).
try
{
_thread.join();
}
catch (InterruptedException e)
{
// Ignore.
}
}
private final EventHandlerThread _thread;
}
static final class InterruptWorkItem implements ThreadPoolWorkItem
{
@Override
public void execute(ThreadPoolCurrent current)
{
// Nothing to do, this is just used to interrupt the thread pool selector.
}
}
private static ThreadPoolWorkItem _interruptWorkItem = new InterruptWorkItem();
//
// Exception raised by the thread pool work queue when the thread pool is destroyed.
//
static final class DestroyedException extends RuntimeException
{
public static final long serialVersionUID = 0L;
}
public
ThreadPool(Instance instance, String prefix, int timeout)
{
com.zeroc.Ice.Properties properties = instance.initializationData().properties;
_instance = instance;
_dispatcher = instance.initializationData().dispatcher;
_destroyed = false;
_prefix = prefix;
_selector = new Selector(instance);
_threadIndex = 0;
_inUse = 0;
_inUseIO = 0;
_promote = true;
_serialize = properties.getPropertyAsInt(_prefix + ".Serialize") > 0;
_serverIdleTime = timeout;
_threadPrefix = Util.createThreadName(properties, _prefix);
int nProcessors = Runtime.getRuntime().availableProcessors();
//
// We use just one thread as the default. This is the fastest
// possible setting, still allows one level of nesting, and
// doesn't require to make the servants thread safe.
//
int size = properties.getPropertyAsIntWithDefault(_prefix + ".Size", 1);
if(size < 1)
{
String s = _prefix + ".Size < 1; Size adjusted to 1";
_instance.initializationData().logger.warning(s);
size = 1;
}
int sizeMax = properties.getPropertyAsIntWithDefault(_prefix + ".SizeMax", size);
if(sizeMax == -1)
{
sizeMax = nProcessors;
}
if(sizeMax < size)
{
String s = _prefix + ".SizeMax < " + _prefix + ".Size; SizeMax adjusted to Size (" + size + ")";
_instance.initializationData().logger.warning(s);
sizeMax = size;
}
int sizeWarn = properties.getPropertyAsInt(_prefix + ".SizeWarn");
if(sizeWarn != 0 && sizeWarn < size)
{
String s = _prefix + ".SizeWarn < " + _prefix + ".Size; adjusted SizeWarn to Size (" + size + ")";
_instance.initializationData().logger.warning(s);
sizeWarn = size;
}
else if(sizeWarn > sizeMax)
{
String s = _prefix + ".SizeWarn > " + _prefix + ".SizeMax; adjusted SizeWarn to SizeMax (" + sizeMax + ")";
_instance.initializationData().logger.warning(s);
sizeWarn = sizeMax;
}
int threadIdleTime = properties.getPropertyAsIntWithDefault(_prefix + ".ThreadIdleTime", 60);
if(threadIdleTime < 0)
{
String s = _prefix + ".ThreadIdleTime < 0; ThreadIdleTime adjusted to 0";
_instance.initializationData().logger.warning(s);
threadIdleTime = 0;
}
_size = size;
_sizeMax = sizeMax;
_sizeWarn = sizeWarn;
_sizeIO = Math.min(sizeMax, nProcessors);
_threadIdleTime = threadIdleTime;
int stackSize = properties.getPropertyAsInt( _prefix + ".StackSize");
if(stackSize < 0)
{
String s = _prefix + ".StackSize < 0; Size adjusted to JRE default";
_instance.initializationData().logger.warning(s);
stackSize = 0;
}
_stackSize = stackSize;
boolean hasPriority = properties.getProperty(_prefix + ".ThreadPriority").length() > 0;
int priority = properties.getPropertyAsInt(_prefix + ".ThreadPriority");
if(!hasPriority)
{
hasPriority = properties.getProperty("Ice.ThreadPriority").length() > 0;
priority = properties.getPropertyAsInt("Ice.ThreadPriority");
}
_hasPriority = hasPriority;
_priority = priority;
_workQueue = new ThreadPoolWorkQueue(_instance, this, _selector);
_nextHandler = _handlers.iterator();
if(_instance.traceLevels().threadPool >= 1)
{
String s = "creating " + _prefix + ": Size = " + _size + ", SizeMax = " + _sizeMax + ", SizeWarn = " +
_sizeWarn;
_instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s);
}
try
{
for(int i = 0; i < _size; i++)
{
EventHandlerThread thread = new EventHandlerThread(_threadPrefix + "-" + _threadIndex++);
if(_hasPriority)
{
thread.start(_priority);
}
else
{
thread.start(java.lang.Thread.NORM_PRIORITY);
}
_threads.add(thread);
}
}
catch(RuntimeException ex)
{
String s = "cannot create thread for `" + _prefix + "':\n" + Ex.toString(ex);
_instance.initializationData().logger.error(s);
destroy();
try
{
joinWithAllThreads();
}
catch (InterruptedException e)
{
throw new com.zeroc.Ice.OperationInterruptedException();
}
throw ex;
}
}
@SuppressWarnings("deprecation")
@Override
protected synchronized void
finalize()
throws Throwable
{
try
{
com.zeroc.IceUtilInternal.Assert.FinalizerAssert(_destroyed);
}
catch(java.lang.Exception ex)
{
}
finally
{
super.finalize();
}
}
public synchronized void
destroy()
{
if(_destroyed)
{
return;
}
_destroyed = true;
_workQueue.destroy();
}
public synchronized void
updateObservers()
{
for(EventHandlerThread thread : _threads)
{
thread.updateObserver();
}
}
public synchronized void
initialize(final EventHandler handler)
{
assert(!_destroyed);
_selector.initialize(handler);
handler.setReadyCallback(
new ReadyCallback()
{
public void ready(int op, boolean value)
{
synchronized(ThreadPool.this)
{
if(_destroyed)
{
return;
}
_selector.ready(handler, op, value);
}
}
});
}
public void
register(EventHandler handler, int op)
{
update(handler, SocketOperation.None, op);
}
public synchronized void
update(EventHandler handler, int remove, int add)
{
assert(!_destroyed);
// Don't remove what needs to be added
remove &= ~add;
// Don't remove/add if already un-registered or registered
remove = handler._registered & remove;
add = ~handler._registered & add;
if(remove == add)
{
return;
}
_selector.update(handler, remove, add);
}
public void
unregister(EventHandler handler, int op)
{
update(handler, op, SocketOperation.None);
}
public synchronized boolean
finish(EventHandler handler, boolean closeNow)
{
assert(!_destroyed);
closeNow = _selector.finish(handler, closeNow);
_workQueue.queue(new FinishedWorkItem(handler, !closeNow));
return closeNow;
}
public void
dispatchFromThisThread(DispatchWorkItem workItem)
{
if(_dispatcher != null)
{
try
{
_dispatcher.accept(workItem, workItem.getConnection());
}
catch(java.lang.Exception ex)
{
if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1)
{
java.io.StringWriter sw = new java.io.StringWriter();
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
ex.printStackTrace(pw);
pw.flush();
_instance.initializationData().logger.warning("dispatch exception:\n" + sw.toString());
}
}
}
else
{
workItem.run();
}
}
synchronized public void
dispatch(DispatchWorkItem workItem)
{
if(_destroyed)
{
throw new com.zeroc.Ice.CommunicatorDestroyedException();
}
_workQueue.queue(workItem);
}
public void
joinWithAllThreads()
throws InterruptedException
{
//
// _threads is immutable after destroy() has been called,
// therefore no synchronization is needed. (Synchronization
// wouldn't be possible here anyway, because otherwise the
// other threads would never terminate.)
//
for(EventHandlerThread thread : _threads)
{
thread.join();
}
//
// Destroy the selector
//
_selector.destroy();
}
//
// Implement execute method from java.util.concurrent.Executor interface
//
@Override
public void execute(Runnable command)
{
dispatch(new com.zeroc.IceInternal.DispatchWorkItem()
{
@Override
public void run()
{
command.run();
}
});
}
private void
run(EventHandlerThread thread)
{
ThreadPoolCurrent current = new ThreadPoolCurrent(_instance, this, thread);
boolean select = false;
while(true)
{
if(current._handler != null)
{
try
{
current._handler.message(current);
}
catch(DestroyedException ex)
{
return;
}
catch(java.lang.Exception ex)
{
String s = "exception in `" + _prefix + "':\n" + Ex.toString(ex);
s += "\nevent handler: " + current._handler.toString();
_instance.initializationData().logger.error(s);
}
}
else if(select)
{
try
{
_selector.select(_serverIdleTime);
}
catch(Selector.TimeoutException ex)
{
synchronized(this)
{
if(!_destroyed && _inUse == 0)
{
_workQueue.queue(new ShutdownWorkItem()); // Select timed-out.
}
continue;
}
}
}
synchronized(this)
{
if(current._handler == null)
{
if(select)
{
_selector.finishSelect(_handlers);
select = false;
_nextHandler = _handlers.iterator();
}
else if(!current._leader && followerWait(current))
{
return; // Wait timed-out.
}
}
else if(_sizeMax > 1)
{
if(!current._ioCompleted)
{
//
// The handler didn't call ioCompleted() so we take care of decreasing
// the IO thread count now.
//
--_inUseIO;
}
else
{
//
// If the handler called ioCompleted(), we re-enable the handler in
// case it was disabled and we decrease the number of thread in use.
//
if(_serialize)
{
_selector.enable(current._handler, current.operation);
}
assert(_inUse > 0);
--_inUse;
}
if(!current._leader && followerWait(current))
{
return; // Wait timed-out.
}
}
//
// Get the next ready handler.
//
current._handler = null;
while(_nextHandler.hasNext())
{
EventHandlerOpPair n = _nextHandler.next();
int op = n.op & ~n.handler._disabled & n.handler._registered;
if(op != 0)
{
current._ioCompleted = false;
current._handler = n.handler;
current.operation = op;
thread.setState(com.zeroc.Ice.Instrumentation.ThreadState.ThreadStateInUseForIO);
break;
}
}
if(current._handler == null)
{
//
// If there are no more ready handlers and there are still threads busy performing
// IO, we give up leadership and promote another follower (which will perform the
// select() only once all the IOs are completed). Otherwise, if there's no more
// threads peforming IOs, it's time to do another select().
//
if(_inUseIO > 0)
{
promoteFollower(current);
}
else
{
_handlers.clear();
_selector.startSelect();
select = true;
thread.setState(com.zeroc.Ice.Instrumentation.ThreadState.ThreadStateIdle);
}
}
else if(_sizeMax > 1)
{
//
// Increment the IO thread count and if there's still threads available
// to perform IO and more handlers ready, we promote a follower.
//
++_inUseIO;
if(_nextHandler.hasNext() && _inUseIO < _sizeIO)
{
promoteFollower(current);
}
}
}
}
}
synchronized void
ioCompleted(ThreadPoolCurrent current)
{
current._ioCompleted = true; // Set the IO completed flag to specify that ioCompleted() has been called.
current._thread.setState(com.zeroc.Ice.Instrumentation.ThreadState.ThreadStateInUseForUser);
if(_sizeMax > 1)
{
--_inUseIO;
if(!_destroyed)
{
if(_serialize)
{
_selector.disable(current._handler, current.operation);
}
}
if(current._leader)
{
//
// If this thread is still the leader, it's time to promote a new leader.
//
promoteFollower(current);
}
else if(_promote && (_nextHandler.hasNext() || _inUseIO == 0))
{
notify();
}
assert(_inUse >= 0);
++_inUse;
if(_inUse == _sizeWarn)
{
String s = "thread pool `" + _prefix + "' is running low on threads\n"
+ "Size=" + _size + ", " + "SizeMax=" + _sizeMax + ", " + "SizeWarn=" + _sizeWarn;
_instance.initializationData().logger.warning(s);
}
if(!_destroyed)
{
assert(_inUse <= _threads.size());
if(_inUse < _sizeMax && _inUse == _threads.size())
{
if(_instance.traceLevels().threadPool >= 1)
{
String s = "growing " + _prefix + ": Size=" + (_threads.size() + 1);
_instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s);
}
try
{
EventHandlerThread thread = new EventHandlerThread(_threadPrefix + "-" + _threadIndex++);
_threads.add(thread);
if(_hasPriority)
{
thread.start(_priority);
}
else
{
thread.start(java.lang.Thread.NORM_PRIORITY);
}
}
catch(RuntimeException ex)
{
String s = "cannot create thread for `" + _prefix + "':\n" + Ex.toString(ex);
_instance.initializationData().logger.error(s);
}
}
}
}
}
private synchronized void
promoteFollower(ThreadPoolCurrent current)
{
assert(!_promote && current._leader);
_promote = true;
if(_inUseIO < _sizeIO && (_nextHandler.hasNext() || _inUseIO == 0))
{
notify();
}
current._leader = false;
}
private synchronized boolean
followerWait(ThreadPoolCurrent current)
{
assert(!current._leader);
current._thread.setState(com.zeroc.Ice.Instrumentation.ThreadState.ThreadStateIdle);
//
// It's important to clear the handler before waiting to make sure that
// resources for the handler are released now if it's finished. We also
// clear the per-thread stream.
//
current._handler = null;
current.stream.reset();
//
// Wait to be promoted and for all the IO threads to be done.
//
while(!_promote || _inUseIO == _sizeIO || (!_nextHandler.hasNext() && _inUseIO > 0))
{
if(_threadIdleTime > 0)
{
long before = Time.currentMonotonicTimeMillis();
boolean interrupted = false;
try
{
//
// If the wait is interrupted then we'll let the thread die as if it timed out.
//
wait(_threadIdleTime * 1000);
}
catch (InterruptedException e)
{
interrupted = true;
}
if(interrupted || Time.currentMonotonicTimeMillis() - before >= _threadIdleTime * 1000)
{
if(!_destroyed && (!_promote || _inUseIO == _sizeIO || (!_nextHandler.hasNext() && _inUseIO > 0)))
{
if(_instance.traceLevels().threadPool >= 1)
{
String s = "shrinking " + _prefix + ": Size=" + (_threads.size() - 1);
_instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s);
}
assert(_threads.size() > 1); // Can only be called by a waiting follower thread.
_threads.remove(current._thread);
_workQueue.queue(new JoinThreadWorkItem(current._thread));
return true;
}
}
}
else
{
try
{
wait();
}
catch (InterruptedException e)
{
//
// Eat the InterruptedException.
//
}
}
}
current._leader = true; // The current thread has become the leader.
_promote = false;
return false;
}
private final Instance _instance;
private final java.util.function.BiConsumer _dispatcher;
private final ThreadPoolWorkQueue _workQueue;
private boolean _destroyed;
private final String _prefix;
private final String _threadPrefix;
private final Selector _selector;
final class EventHandlerThread implements Runnable
{
EventHandlerThread(String name)
{
_name = name;
_state = com.zeroc.Ice.Instrumentation.ThreadState.ThreadStateIdle;
updateObserver();
}
public void
updateObserver()
{
// Must be called with the thread pool mutex locked
com.zeroc.Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer;
if(obsv != null)
{
_observer = obsv.getThreadObserver(_prefix, _name, _state, _observer);
if(_observer != null)
{
_observer.attach();
}
}
}
public void
setState(com.zeroc.Ice.Instrumentation.ThreadState s)
{
// Must be called with the thread pool mutex locked
if(_observer != null)
{
if(_state != s)
{
_observer.stateChanged(_state, s);
}
}
_state = s;
}
public void
join()
throws InterruptedException
{
_thread.join();
}
public void
start(int priority)
{
_thread = new Thread(null, this, _name, _stackSize);
_thread.setPriority(priority);
_thread.start();
}
@Override
public void
run()
{
if(_instance.initializationData().threadStart != null)
{
try
{
_instance.initializationData().threadStart.run();
}
catch(java.lang.Exception ex)
{
String s = "threadStart method raised an unexpected exception in `";
s += _prefix + "' thread " + _name + ":\n" + Ex.toString(ex);
_instance.initializationData().logger.error(s);
}
}
try
{
ThreadPool.this.run(this);
}
catch(java.lang.Exception ex)
{
String s = "exception in `" + _prefix + "' thread " + _name + ":\n" + Ex.toString(ex);
_instance.initializationData().logger.error(s);
}
if(_observer != null)
{
_observer.detach();
}
if(_instance.initializationData().threadStop != null)
{
try
{
_instance.initializationData().threadStop.run();
}
catch(java.lang.Exception ex)
{
String s = "threadStop method raised an unexpected exception in `";
s += _prefix + "' thread " + _name + ":\n" + Ex.toString(ex);
_instance.initializationData().logger.error(s);
}
}
}
Thread getThread()
{
return _thread;
}
final private String _name;
private Thread _thread;
private com.zeroc.Ice.Instrumentation.ThreadState _state;
private com.zeroc.Ice.Instrumentation.ThreadObserver _observer;
}
private final int _size; // Number of threads that are pre-created.
private final int _sizeIO; // Number of threads that can concurrently perform IO.
private final int _sizeMax; // Maximum number of threads.
private final int _sizeWarn; // If _inUse reaches _sizeWarn, a "low on threads" warning will be printed.
private final boolean _serialize; // True if requests need to be serialized over the connection.
private final int _priority;
private final boolean _hasPriority;
private final long _serverIdleTime;
private final long _threadIdleTime;
private final int _stackSize;
private java.util.List _threads = new java.util.ArrayList<>();
private int _threadIndex; // For assigning thread names.
private int _inUse; // Number of threads that are currently in use.
private int _inUseIO; // Number of threads that are currently performing IO.
private java.util.List _handlers = new java.util.ArrayList<>();
private java.util.Iterator _nextHandler;
private boolean _promote;
}