Threads and Executors - igniterealtime/Smack GitHub Wiki
Current Threads/Executors
AbstractXMPPConnection
removeCallbacksService
(SingleThreadedScheduledExecutor, minSize=1, maxSize=1) used to remove pending callbacks after a timeoutcachedExecutorService
(CachedThreadPool, minSize=0, maxSize=inf) used for Smack's asyncGo() API, which includes async listenerssingleThreadedExecutorService
(SingleThreadExecutor, minSize=1, maxSize=1) used to invoke listeners, queue size Integer.MAX_INT, minSize set to '0' in Smack 4.2.4- Removed in Smack 4.2.4
executorService
(ThreadPoolExecutor, minSize=1, maxSize=1) used to invoke collectors and eventually a singleThreadedExecutor for listeners, has a queue size of 100
XMPPTCPConnection
- reader thread
- writer thread
PingManager
- executorService (SingleThreadedScheduledExecutor, minSize=1, maxSize=1) used to schedule server pings
Thoughts
- XMPPTCPConnection could use NIO and therefore use a single thread. But needs to keep the bundle-and-defer feature.
- sharing cachedExecutorService accross connections yields no benefit, as it's min core pool size is 0
- remove callbacks service could eventually be shared
- executorService's main (/only?) purpose is being a buffer, i.e. its queue. The other reason it exists is that it's core pool size is one, i.e. there is always one thread ready for work
Possible Savings
Current min threads per XMPPTCPConnection + PingManager: Min: 6
- -1 - Use NIO in XMPPTCPConnection, makes XMPPTCPconnection use one thread for read/write
- -2 - use below data structure to replace
executorService
andsingleThreadedExecutorService
- -1 - Share remove callbacks service, i.e. make it static (and ensure that it doesn't block VM termination, use daemon threads)
- -1 - Shared pingManager scheduled executor (and ensure that it doesn't block VM termination, use daemon threads, also ensure that it doesn't cause memory leaks, eventually use weak refs)
Achievable min threads: 1 1x thread for XMPPTCPConnection NIO reader/writer
MultipleQueueNonConcurrentExecutionThreadSharingExecutor
DRAFT/WIP: May summons dragons when implemented and executed.
AtomicInteger queuesState;
put(Runnable runnable, int queueID) {
queues[queueID].put(runnable);
queuesState++;
if (!inExecution[queueId] && currentWorkers < maxWorkers) {
// create new worker
}
}
workerLoop() {
Runnable work = null;
int savedQueueState = queuesState;
for (int i = 0; i < maxQueues; i++)
synchronized (queues[i]) {
if (queues[i].isEmpty()) continue;
if (inExecution[i]) continue;
work = queues[i].pop();
inExecution[i] = true;
}
work();
inExecution[i] = false;
}
synchronized (this) {
if (savedQueuedState == queuesState) // if no new work
if (currentWorkers > minWorkers) {
currentWorkers--;
return;
} else {
// sleep until new work
}
}
}
}