This document describes how to work with a thread pool.
Auto-shrinking
After some time of work, idle threads in the pool may increase their number much above the minimum. That’s why an auto-shrinking mechanism is implemented – every 30 seconds (or the value of the mbs.util.threadpool.inactiveTime system property) the ThreadPoolManager service checks the threads in the pool and if needed reduces the idle threads number to the number of accessed threads within this time period. If accessed threads are less than the minimum, idle threads count is shrunk to the defined minimum.
Ways of Threads Allocation
The ThreadPoolManager service supports two approaches for allocating threads from the thread pool:
This operation can be done by using the ThreadPoolFactory, available as a com.prosyst.util.threadpool.ThreadPoolFactory service object in the OSGi framework. The factory's only method getThreadPool provides restricted access to the thread pool – the caller bundle can use no more threads than the number or percent specified when the getThreadPool method has been invoked.
Bundles can refer directly to the Thread Pool Manager, available as a com.prosyst.util.threadpool.ThreadPoolManager service object in the OSGi framework, to use threads from its thread pool. In such case, the Thread Pool Manager allows the caller bundle to use up to 30% (or the percent specified through the mbs.util.threadpool.percent system property) of the threads in the pool.
In both ways it becomes possible to avoid having all pool's threads allocated by a single bundle. The bundle is not allowed to take concurrently more threads than the number specified earlier to the ThreadPoolManager service. If the bundle requests a thread over the indicated limit, the request will wait until the bundle reduces consumed threads. Then, the job will be queued up in the pool of waiting jobs.
Executing a Runnable Job
A Runnable job can be executed within the thread pool by passing it in the corresponding execute method of the ThreadPoolManager instance either returned by the ThreadPoolFactoryservice or got as a service from the OSGi framework. The ThreadPoolManager service allows setting different priorities of its subordinate threads as well as, depending on the mbs.util.threadpool.useNames system property, naming each executed job.
The code example below contains two components:
The job is simple and common – in order to process an operation, it waits for an event to occur; if the event does not occur within a certain time period (1 second in the example), another operation is loaded. In the example below, the event is the turning on of the check flag and all operations are related to printing messages in the system output.
Listing 1. The Runnable Object example.
public class RunnableTest implements Runnable {
private Object synch;
private boolean check;
//Constructs a test job
public RunnableTest() {
check = false;
synch = new Object();
}
//This method is executed by the Thread Pool Manager service
public void run() {
synchronized(synch) {
System.out.println("Job "
+ Thread.currentThread().getName()
+ " starts running!");
if (!check) {
try {
synch.wait(1000);
} catch (InterruptedException e) { }
}
if (check) {
System.out.println("OK: CHECKED");
} else {
System.out.println("NOT OK: NOT CHECKED");
}
}
}
//Turns the check flag on
public void checkIt() {
synchronized (synch) {
check = true;
synch.notify();
}
}
//Wakes up this Runnable object causing exiting its run method
public void stopIt() {
synchronized (synch) {
synch.notify();
}
}
}
Listing 2. Using the Thread Pool Manager.
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import com.prosyst.util.threadpool.ThreadPoolManager;
public class TestActivator implements BundleActivator {
ServiceReference tpoolManRef;
ThreadPoolManager tpoolMan;
private static String servName = ThreadPoolManager.class.getName();
public void start(BundleContext bc) throws BundleException {
// Retrieving the Thread Pool Manager from the OSGi framework
tpoolManRef = bc.getServiceReference(servName);
if(tpoolManRef != null) {
tpoolMan = (ThreadPoolManager) bc.getService(tpoolManRef);
// Starting the execution of the RunnableTest job
tpoolMan.execute(new RunnableTest(), "test");
} else {
throw new BundleException("No service reference is available!");
}
}
public void stop(BundleContext bc) {
bc.ungetService(tpoolManRef);
}
}
Accessing Runnable Instances
If the thread that an entity operates in is taken from the pool of the ThreadPoolManager service, the entity can retrieve the associated Runnable job and make use of some additional functionality, offered by the job. Each thread in the thread pool is a com.prosyst.util.threadpool.ThreadContext instance whose getRunnable method returns the job presently attached to this thread.
Listing 3. Getting the current Runnable object from the thread pool.
. . .
Thread current = Thread.currentThread();
if (current instanceof ThreadContext) {
Runnable runnable = ((ThreadContext) current).getRunnable();
}
. . .
System Properties
The system properties, that can be set for the operation of the Database, are described in the Setup Guide.