if we look inside DefaultThreadFactory of Jgroups the following code is present
protected Thread newThread(Runnable r,String name,String addr,String cluster_name) {
String thread_name=getNewThreadName(name, addr, cluster_name);
Thread retval=new Thread(r, thread_name);
retval.setDaemon(createDaemons);
return retval;
}
As new thread is used so I believe in a managed server environment this can cause issues and is also not a good practice.
If I just replace the default thread factories and executors with Managed factories and executors of WebSphere will the behavior of Jgroups be still the same ?
Any pointers will be helpful ..?
Update
My intention is to use JGroups with WebSphere AS 8.5. I am keen to not have any un-managed threads. My main use case is for leader election and some message passing. It will be used to manage Spring Integration pollers and ensure only one poller is running within the cluster.
WAS 8.5 still uses the CommonJ api for Work management.
I am using Spring to abstract the Task Executors and Schedulers.
It was initially easy enough to replace the ThreadPools with task executors as they share the Executor api.
The TaskScheduler had to be adapted to work with your TimeScheduler interface. They are very similar and perhaps extending from the ScheduledExecutorService could be an option here. I implemented to your interface and delegated to Springs TaskScheduler.
The main issue is with the ThreadFactory. CommonJ does not have this concept. For this I created a ThreadWrapper that encapsulates the Runnable and delegates out to a TaskExecutor when the "Thread's" start method is called. I ignored the thread renaming functionality as this will not have any effect.
public Thread newThread(Runnable command) {
log.debug("newThread");
RunnableWrapper wrappedCommand = new RunnableWrapper(command);
return new ThreadWrapper(taskExecutor, wrappedCommand);
}
public synchronized void start() {
try {
taskExecutor.execute(runnableWrapper);
} catch (Exception e) {
throw new UnableToStartException(e);
}
}
This is where I ran into problems. The issues were in the transports. In a number of cases with in the run method of some of the internal runnables e.g. the DiagnosticsHandler, the TransferQueueBundler of TP and ViewHandler of GMS there is a while statements that checks the thread.
public class DiagnosticsHandler implements Runnable {
public void run() {
byte[] buf;
DatagramPacket packet;
while(Thread.currentThread().equals(thread)) {
//...
}
}
}
protected class TransferQueueBundler extends BaseBundler implements Runnable {
public void run() {
while(Thread.currentThread() == bundler_thread) {
//...
}
}
}
class ViewHandler implements Runnable {
public void run() {
long start_time, wait_time; // ns
long timeout=TimeUnit.NANOSECONDS.convert(max_bundling_time, TimeUnit.MILLISECONDS);
List<Request> requests=new LinkedList<>();
while(Thread.currentThread().equals(thread) && !suspended) {
//...
}
}
}
This does not co-operate with our thread wrapping. If this could be altered so that the equals method is called on the stored thread it would be possible to override it.
As you can see from the various snippets there are various implementations and levels of protections varying from package, protected and public. This is increased the difficulty of extending the classes.
With all of this done it still did not remove completely the issue of unmanaged threads.
I was using the properties file method of creating the protocol stack. This initialises the protocol stack once the properties are set. To remove the Timer threads that are created by the bottom protocol. The TimeScheduler must be set prior the to stack being initialised.
Once this is done the threads are all managed.
Do you have any suggestions on how this could have been achieved more easily?