To make a long story short, I'm having trouble getting a couple of Java RMI's non-daemon threads to close out after my application no longer needs RMI. This prevents the JVM from exiting when main() completes.
I understand that exporting UnicastRemoteObjects will cause RMI to leave threads open until you successfully call UnicastRemoteObject.unexportObject(Object o,boolean force). Here's an example (run without modification and the JVM will exit normally - remove the call to unexportObject and the JVM will never exit):
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class TestUnicastRemoteObject{
private static UnicastRemoteObject obj;
private static Registry registry;
public static void main(String[] args) throws Exception{
obj = new UnicastRemoteObject(){
private static final long serialVersionUID = 1L;
};
System.err.println("created UnicastRemoteObject");
System.err.println("creating registry ...");
registry = LocateRegistry.createRegistry(9999);
System.err.println("registry created.");
System.err.println("binding obj to registry ...");
registry.bind("Test", obj);
System.err.println("bound");
UnicastRemoteObject.unexportObject(obj, true);
System.err.println("unexported obj");
}
}
Also, it doesn't seem to matter whether you create the registry and/or bind the remote object to it - the only thing that seems to matter in this example is that any time you create a UnicastRemoteObject, you need to call unexportObject in order to prevent any threads from remaining after you're done.
In my application, I've made sure that I've called unexportObject on every UnicastRemoteObject I create, and yet RMI's "reaper" thread and "connection accept" thread still persist, preventing my JVM from exiting when my application is finished using RMI resources.
Is there something else that could cause RMI to leave threads behind, aside from forgetting to unexport UnicastRemoteObjects?
Sure enough, I had a bug in the code that caused one of my (many) UnicastRemoteObjects to not unexport itself when the calling application was done utilizing it. So the answer is:
Unexporting all UnicastRemoteObjects within a running JVM is sufficient to close all RMI non-daemon threads.
Sounds like you solved you problem #Ben but for posterity, I thought I'd promote my comment to an answer. Whenever I have a register/unregister type of pattern I make sure to manage them through a singleton object. This way you have one place to go to figure out which object was not unregistered. Exposing this in JMX is also a win.
Something like the following code would be good. It will allow you to log or JMX query to see what objects have been bound to the registry but have yet to be unbound.
public class UnicastRegistry {
private static Registry registry;
private static UnicastRegistry singleton;
// private to force the singleton
private UnicastRegistry() throws RemoteException {
registry = LocateRegistry.createRegistry(9977);
}
public static UnicastRegistry createSingleton() throws RemoteException {
if (singleton == null) {
singleton = new UnicastRegistry();
}
return singleton;
}
public void register(String label, Remote obj) throws Exception {
registry.bind(label, obj);
}
public void unregister(String label) throws Exception {
Remote remote = registry.lookup(label);
registry.unbind(label);
if (remote instanceof UnicastRemoteObject) {
UnicastRemoteObject.unexportObject(remote, true);
}
}
public void unregisterAll() throws Exception {
for (String label : registry.list()) {
unregister(label);
}
}
public void printStillBound() throws Exception {
String[] stillBound = registry.list();
if (stillBound.length > 0) {
System.out.println("Still bound = " + Arrays.toString(stillBound));
}
}
}
Related
I know I'm new to this spring stuff but I've been stuck on this all day. I don't much like asking questions but maybe I'll get an idea.
So here's my problem:
I'm trying to create a Queue for processing stuff on the back end. I did this by creating a static executorservice in a component class with helper methods to run them. it seems to work like i want, and when i wire in classes i can get into those classes, but it seems like when those are running they lose application context (or something this is just my guess).
I'm sure There are better ways to do this, but in the custom framework I am working in there are a number of features that will not work for me. I have no spring-config.xml, cannot use #Configuration
executor service component
#Component
public class FifoComponent {
public static ExecutorService executors = Executors.newSingleThreadExecutor();
private static Lock lock = new ReentrantLock(true);
public static void executeNewTestJob(int i) {
lock.lock();
OrderAllocationTestJob job = new OrderAllocationTestJob(i);
executors.execute(job);
lock.unlock();
}
}
Runnable component - note appdateutils has a method that calls a component that and works fine in my typical tomcat environment
#Component
public class OrderAllocationTestJob implements Runnable {
int i;
public OrderAllocationTestJob(int i) {
this.i = i;
}
#Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Asynchronous task " + i);
System.out.println(AppDateUtils.getCurrentTimeStamp());
}
}
call from a struts 2 action (test) i know I can call the appdateutils.gettime method from
for (int i = 0; i < 50; i++) {
FifoComponent.executeNewTestJob(i);
}
here's the exception i end up with for what it's worth
"Scope 'request' is not active for the current thread"
Exception in thread "pool-15-thread-50" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dateTimestampDao': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
"I'm sure There are better ways to do this"
Based on this, you'll need to create/lookup all request and session scoped components before call another thread. Actually, request injection is thread local and can't works in your scenario.
i think if u remove
Thread.sleep(100);
in OrderAllocationTestJob to
job.sleep(100);
in FifoComponent will fix your problem
I solved this solution by extending ConcurrentLinkedQueue for my runnables and keeping them in a manager I instantiated in the initialize method of a ServletContextListener. By overriding the offer() method of the ConcurrentLinkedQueue to continually poll until the queue was empty I was able synchronously process runnables.
Unfortunately this locks down the request thread until the runnable is done and I will have to have my users keep an eye on it and let me know if the pages end up running long, but at least in my test environment the process seems sub-second even when i hit it with 20 at a time so I'm OK for now.
I would still prefer an ExecutorService executed from my Tomcat container but outside the scope of the requests but unless someone can answer the question I'm just going to have to leave it for now
Are you looking something like that?
#Component
public class AsynchronousThread extends Thread {
public static final Logger LOGGER = LoggerFactory
.getLogger(AsynchronousThread.class);
#Autowired
private Writer writer;
private BlockingQueue<IndexContextDTO> blockingQueue = new LinkedBlockingQueue<IndexContextDTO>(
500);
/**
*
*/
public AsynchronousThread() {
super("AsynchronousThread");
}
#PostConstruct
public void init() {
Integer internalQueueSize = 100;
this.blockingQueue = new LinkedBlockingQueue<>(internalQueueSize);
this.start();
}
#Override
public void run() {
while (true) {
// Do stuff
}
}
public void putInQueue(IndexContextDTO message) {
try {
this.blockingQueue.put(message);
} catch (InterruptedException interruptedException) {
// This exception will be thrown in very rare case.
LOGGER.error("An error while putting message in the queue. "
+ message, interruptedException);
}
}
}
i have Server side i tried to make it Singeltone in order to accses server metodtds from another classes, but when i run server main and then i do Server.getInstance() from another class it throws this expection:
Exception in thread "main"
java.net.BindException: Address already in use: JVM_Bind
i tried a lot of things but its not working
private static Server serverinstance = null;
private static Object obj=new Object();
public Server() throws IOException {
server = new ServerSocket(222);
hash = new HashMap<String, SocketData>();
}
public static Server getInstance() throws IOException {
synchronized (obj) {
if (serverinstance == null) {
serverinstance = new Server();
serverinstance.listenServer();
}
return serverinstance;
}
}
private void listenServer() throws IOException {
while (flag) {
ans = server.accept();
if (serverinstance != null)
new EchoThread(serverinstance, ans);
}
}
public static void main(String args[]) throws IOException {
Server.getInstance();
}
Class A()
{
public A()
{
Server.getInstance();
}
}
Try restarting your computer. That is because another program is already using port 222, so your program is unable to listen on it. If that doesn't work, try switching 222 to something different, like maybe 8000 or 9999, basically any number from 1000-65535 (0-65535 if you are on Windows)
Java singleton guarantees one instance only per JVM and per ClassLoader.
In your case you are loading the same Server class into two different JVM and Classloaders by invoking two separate main methods. This causes the Server constructor to be called twice that in turn tries to create two ServerSocket on the same 222 port.
One quick solution is to have class A be created directly or indirectly from the main method that is calling Server.getInstance();.
The problem is, that I stop Dropwizard application (via ctrl + c) and I have inserted a Shutdown Hook in main class to do some stuff before shutdown. But now ServerConnector for the application is closed before I can do what I want to do.
There is a polling service (polls one of my resources) and I need to tell them, that application will go down soon to prevent some problems. I need at least 15 seconds before ressource goes down.
Some idea how to solve this problem?
You can use a lifecycle hook to manage certain resources.
public class ManagedObject implements Managed {
private final Object obj;
public ManagedObject(Object obj) {
this.obj = obj;
}
#Override
public void start() throws Exception {
// Do something to start the object
}
#Override
public void stop() throws Exception {
// Do something to stop the object
}
}
Then register on the environment
ManagedObject myManagedObject = new ManagedObject(obj);
environment.lifecycle().manage(myManagedObject);
Add a Dropwizard Task that will change the state of a static field (or however you want to pass the data) which your polling resource will be using to respond.
public class ShutdownTask extends Task {
private int timeoutSeconds;
public ShutdownTask (int timeoutSeconds) {
super("shutdown");
this.timeoutSeconds = timeoutSeconds;
}
#Override
public void execute(ImmutableMultimap<String, String> parameters, PrintWriter output) throws Exception {
// you probably can take the timeout parameter from the request via 'parameters' instead of the constructor.
PollingResource.shuttingDownIn = timeoutSeconds;
}
}
environment.admin().addTask(new ShutdownTask(15));
Then write a bash script which will curl to task
curl -X POST http://dw.example.com:8081/tasks/shutdown
And:
This is probably not recommended (people don't like System.exit(0)) but you can add the following to execute method:
Thread.sleep(timeoutSeconds * 1000);
System.exit(0)
Or do the waiting and kill the dropwizard app in the bash script.
kill -SIGINT <pid>
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
** See updates first as original implemenation contains some false assumptions
Backstory
I have a problem where I MUST fork the processes, the reason is that I am using the jni and the single threaded R process. Also I need a way to monitor memory and cpu, forking seems like the only real solution. You cannot implement have more than one R invocation per process, I have definitly tried to get around this limitation but am pretty sure it is not possible due to the rinside setup method.
Current implementation
I am currently trying to fork a process and connect an rmi connection to it and store these in a stacked pool. The problem is that the registry.bind() method is not blocking as it should. When binding to the registry in a main process the process will block and wait for remote method calls but when starting from a RunTime.getRuntime().exec() the process does not block and exits. This causes my endpoint daemon to close and I receive socket errors when trying to communicate with the daemon. I am using the gfork library to fork my process simply for ability to receive exceptions and such on startup of the forked process.
public class JRIDaemon implements IROperationRemoteProvider, Serializable, Runnable {
/**
* Serialization Id
*/
private static final long serialVersionUID = 2279972098306474322L;
/**
* Daemon logger
*/
private static final Logger logger = Logger.getLogger(JRIDaemon.class.getName());
/**
* This is the exeuctor service used to execute our job, the option for
* newSingleThreadExecutor is important because R is single threaded and JRI
* puts check in and will kill us if the thread is manipulated.
*/
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
/**
* This implemenation uses the exeuctor service to run the analytics
* operation. The executor service is used because R is single threaded and
* cannot be called from outside.
*/
private JRIExecutionTask callableOperation;
/**
* This is the unique id that can to fetch this daemon.
*/
private final String daemonId;
private JRIDaemon() {
this(UUID.randomUUID().toString());
}
private JRIDaemon(String daemonId) {
this.daemonId = daemonId;
}
private String getDaemonId() {
return daemonId;
}
#Override
public void run() {
logger.info("Starting the jri daemon");
System.out.println("Starting the jri daemon");
try {
IROperationRemoteProvider stub = (IROperationRemoteProvider) UnicastRemoteObject.exportObject(this, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(daemonId, stub);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Exception occurred when initializing the rmi agent ", e);
}
System.out.println("Daemon is done");
logger.fine("Exiting JRIDaemon#run");
}
/**
* Close the connection to R services.
* #throws NotBoundException
* #throws RemoteException
* #throws AccessException
*/
public void close() throws Exception {
logger.info("Calling close !!!!!!!!!");
//if (registry != null) {
// registry.unbind(daemonId);
//}
//System.exit(0);
}
/**
* #see IROperationProvider#execute(IAnalyticsOperation, List, List)
*/
#Override
public Map<String, IMetric> execute(IAnalyticsOperation operation, List<IAnalyticsOperationInput> inputs, List<? extends IDataProvider> dataProvider) throws Exception {
callableOperation = new JRIExecutionTask(inputs, operation, dataProvider);
Future<Map<String, IMetric>> execution = executorService.submit((Callable<Map<String, IMetric>>) callableOperation);
return execution.get();
}
/**
* #see IROperationProvider#interrupt()
*
* TODO come to a solution on stopping and restarting the thread in the
* Rengine implementation.
*/
#Override
public void interrupt() {
System.out.println("Calling interrupt on executor service");
executorService.shutdown();
// Can't do this yet because it causes a segfault in the task engine
// process.
// callableOperation.interrupt();
}
#Override
public Boolean isAllGood() {
return true;
}
#Override
public void activate() {
}
#Override
public void passivate() {
}
/**
* This is here only for testing purposes.
* #param args
* #throws Exception
*/
public static void main(String args[] ) throws Exception {
IROperationRemoteProvider provider = create();
Thread.sleep(10000);
System.out.println(" ALL GOOD " + provider.isAllGood());
}
/**
* This creates a daemon and initializes returns the client that can be used
* to talk to the server. The daemon is useless for the calling process as
* it is a separate process and we use the client to communicate with the
* jri daemon process.
*
* #return
*/
public static IROperationRemoteProvider create() throws Exception {
LocateRegistry.createRegistry(1099);
String daemonId = UUID.randomUUID().toString();
JRIDaemon daemon = new JRIDaemon(daemonId);
Fork<JRIDaemon, org.gfork.types.Void> forkedDaemon = new Fork<JRIDaemon, org.gfork.types.Void>(daemon);
//forkedDaemon.setJvmOptions("-Djava.security.manager -Djava.security.policy=\"taskenginesecurity.policy\"");
logger.info("Calling run task");
forkedDaemon.addListener(new Listener<JRIDaemon, org.gfork.types.Void>() {
#Override
public void onFinish(Fork<JRIDaemon, Void> fork, boolean wasKilled) throws IllegalAccessException, InterruptedException {
logger.info("Task is finished exit value -> " + fork.getExitValue() + " killed ->" + wasKilled);
}
#Override
public void onError(Fork<JRIDaemon, Void> fork) throws IllegalAccessException, InterruptedException {
logger.info("Error was " + fork.getStdErr());
}
#Override
public void onException(Fork<JRIDaemon, Void> fork) throws IllegalAccessException, InterruptedException, IOException, ClassNotFoundException {
logger.log(Level.SEVERE, " Erorro occurred in daemon ", fork.getException());
}
});
Fork.setLoggingEnabled(true);
forkedDaemon.execute();
forkedDaemon.waitFor();
logger.info("Standard out was " + forkedDaemon.getStdOut());
if (forkedDaemon.isException()) {
throw new RuntimeException("Unble to create Remote Provider ", forkedDaemon.getException());
}
//Thread.sleep(2000);
Registry registry = LocateRegistry.getRegistry();
IROperationRemoteProvider process = (IROperationRemoteProvider) registry.lookup(daemonId);
return process;
}
}
I use the create method to create a new implementation of my analytics provider, the Fork class calls run when it executes to spawn a new daemon. If I put this exact same code in a public static void main(String[] args) the process daemonizes and waits for rmi calls, but when exeting through the for operation it does not.
Here is the Gfrork execute method and you can see it uses the Runtime.exec
/**
* Starts a new java process which runs the task.
* The subprocess inherits the environment including class path an
* system properties of the current process. The JVM is launched using
* executable derived from standard system property 'java.home'.
* <p>
* Standard output (System.out) of the task can be red by {#link #getStdOut()} or
* forwarded to a file, see {#link #setStdOutWriter(Writer)}.
* The same is possible for Standard error (System.err),
* see {#link #getStdErr()} and {#link #setStdErrWriter(Writer)}.
*
* #throws Exception
*/
public synchronized void execute() throws Exception {
if (isExecuting()) {
throw new IllegalStateException(FORK_IS_ALREADY_EXECUTING);
}
exec = Runtime.getRuntime().exec(createCmdArray(), null, workingDir);
taskStdOutReader = new BufferedReader(new InputStreamReader(exec.getInputStream()));
taskErrorReader = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
readError();
readStdOut();
waitForFinishedThread = new Thread("jforkWaitForFinishedThread") {
// needed to notify listeners after execution
#Override
public void run() {
try {
waitFor();
} catch (final Exception e) {
e.printStackTrace();
stdErrText.append(String.format("ERROR jforkListenerNotifier: %s%n", e.toString()));
}
}
};
waitForFinishedThread.start();
}
I have added sleep timers to watch for the process , it does start and shortly after that it exits with no errors and a 0 status. I have verified that if there is a problem configuring rmi in the run method that it will return the exception. RMI seems to be initializing correctly but simply does not block so that the forked process does not exit. I have RTFM on Runtime.exec and have not idea what is causing this to exit. Any help would be appreciated.
Update
Thank you EJP even though your remarks were condescending they were correct. I made an incorrect assumption that the bind was blocking due to the fact that the process did not die but this is rather that it creates a separate thread to handle rmi communication. This is what keeps the process alive.
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class RunnableRMIDaemon implements Remote {
public static void main(String args[]) throws InterruptedException {
String daemonID = "123";
System.out.println("STARTING");
Registry registry;
try {
RunnableRMIDaemon daemon = new RunnableRMIDaemon();
registry = LocateRegistry.getRegistry();
final Remote stub = (Remote) UnicastRemoteObject.exportObject(daemon, 0);
registry.rebind(daemonID, stub);
Thread.sleep(1000);
} catch (RemoteException e) {
throw new RuntimeException("Remote Exception occurred while running " + e);
}
System.out.println("ENDING");
}
}
import java.io.IOException;
public class ForkRMIDaemon {
public static void main(String args[]) throws IOException, InterruptedException {
System.out.println("Starting fork");
Runtime.getRuntime().exec("java -cp . RunnableRMIDaemon");
Thread.sleep(10000);
System.out.println("Completed fork");
}
}
When the first process dies the Runtime.getRuntime().exec() process is still alive.
thanatos:testingrmifork chris$ java ForkRMIDaemon
Starting fork
Completed fork
tv-mini:testingrmifork chris$ ps -ef | grep java
501 25499 1 0 0:00.10 ttys007 0:00.72 /usr/bin/java -cp . RunnableRMIDaemon
501 25501 25413 0 0:00.00 ttys007 0:00.00 grep java
thanatos:testingrmifork chris$
My investigation is not complete yet but it appears the the simple gfork library is actually doing something to close the process on return. I have looked through the gfork code but have not seen where this can be happening.
Thanks EJP and I applogize of the incorrect information. I am guessing that gfork is doing some trickery because it allows you to call a method that is not main.
I assumed that java treated threads more like c pthreads and I have always had to create a while loop in main() otherwise my threads would be killed when main exits. My mistake
The problem is that the registry.bind() method is not blocking as it should. When binding to the registry in a main process the process will block and wait for remote method calls.
No it won't. This is fantasy. You made it up. There is nothing in the documentation that says anything of the sort. It is not a blocking call (except for the moments during which it is communicating with the Registry); and it does not 'block and wait for remote method calls'. It returns to your code. You mustn't be surprised if you make up behaviour and the system doesn't exhibit it.
This causes my endpoint daemon to close
No it doesn't. Your endpoint daemon causes itself to close, somehow. RMI starts non-daemon threads to handle incoming connections, so a JVM that has exported remote objects won't exit until those remote objects are unexported, either explicitly or via GC, or the application calls System.exit(). The way to prevent GC of your remote objects is to store static references to them.
I must say I don't understand why you are even exec-ing a sub-process, if all you are going to do in the main process is wait for it.
Came up with a semi dirty way to do it, this will block indefinitely but I will have to find a sure fire way to close the forked daemon, in a normal environment the process should get a sigkill as when I am running it form unit tests. I think I am almost there.
#Override
public void run() {
logger.info("Starting the jri daemon");
Registry registry;
try {
registry = LocateRegistry.getRegistry();
final IROperationRemoteProvider stub = (IROperationRemoteProvider) UnicastRemoteObject.exportObject(this, 0);
registry.rebind(daemonId, stub);
} catch (RemoteException e) {
throw new RuntimeException("Remote Exception occurred while running " + e);
}
final Object waitObj = new Object();
synchronized (waitObj) {
while (!closed)
try {
waitObj.wait();
} catch (InterruptedException e) {
closed = true;
}
}
logger.fine("Exiting JRIDaemon#run");
}
Regrettably there is no way to specify a timeout when using a regular expression on a String in Java. So if you have no strict control over what patterns get applied to which input, you might end up having threads that consume a lot of CPU while endlessly trying to match (not so well designed) patterns to (malicious?) input.
I'm aware of the reasons why Thread#stop() is deprecated (see http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html). They are centered around objects that might get damaged in case of ThreadDeath exceptions, and which then pollute your running JVM environment and can lead to subtle errors.
My question to anyone who has deeper insight than me into the workings of the JVM is this: If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?
I created a rather defensive solution to be able to process regular expression matching with a timeout. I would be glad for any comment or remark, especially on problems that this approach can cause despite my efforts to avoid them.
Thanks!
import java.util.concurrent.Callable;
public class SafeRegularExpressionMatcher {
// demonstrates behavior for regular expression running into catastrophic backtracking for given input
public static void main(String[] args) {
SafeRegularExpressionMatcher matcher = new SafeRegularExpressionMatcher(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "(x+x+)+y", 2000);
System.out.println(matcher.matches());
}
final String stringToMatch;
final String regularExpression;
final int timeoutMillis;
public SafeRegularExpressionMatcher(String stringToMatch, String regularExpression, int timeoutMillis) {
this.stringToMatch = stringToMatch;
this.regularExpression = regularExpression;
this.timeoutMillis = timeoutMillis;
}
public Boolean matches() {
CallableThread<Boolean> thread = createSafeRegularExpressionMatchingThread();
Boolean result = tryToGetResultFromThreadWithTimeout(thread);
return result;
}
private CallableThread<Boolean> createSafeRegularExpressionMatchingThread() {
final String stringToMatchForUseInThread = new String(stringToMatch);
final String regularExpressionForUseInThread = new String(regularExpression);
Callable<Boolean> callable = createRegularExpressionMatchingCallable(stringToMatchForUseInThread,
regularExpressionForUseInThread);
CallableThread<Boolean> thread = new CallableThread<Boolean>(callable);
return thread;
}
private Callable<Boolean> createRegularExpressionMatchingCallable(final String stringToMatchForUseInThread,
final String regularExpressionForUseInThread) {
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return Boolean.valueOf(stringToMatchForUseInThread.matches(regularExpressionForUseInThread));
}
};
return callable;
}
private Boolean tryToGetResultFromThreadWithTimeout(CallableThread<Boolean> thread) {
startThreadAndApplyTimeout(thread);
Boolean result = processThreadResult(thread);
return result;
}
private void startThreadAndApplyTimeout(CallableThread<Boolean> thread) {
thread.start();
try {
thread.join(timeoutMillis);
} catch (InterruptedException e) {
throwRuntimeException("Interrupt", e);
}
}
private Boolean processThreadResult(CallableThread<Boolean> thread) {
Boolean result = null;
if (thread.isAlive()) {
killThread(thread); // do not use anything from the thread anymore, objects may be damaged!
throwRuntimeException("Timeout", null);
} else {
Exception exceptionOccurredInThread = thread.getException();
if (exceptionOccurredInThread != null) {
throwRuntimeException("Exception", exceptionOccurredInThread);
} else {
result = thread.getResult();
}
}
return result;
}
private void throwRuntimeException(String situation, Exception e) {
throw new RuntimeException(situation + " occured while applying pattern /" + regularExpression + "/ to input '"
+ stringToMatch + " after " + timeoutMillis + "ms!", e);
}
/**
* This method uses {#link Thread#stop()} to kill a thread that is running wild. Although it is acknowledged that
* {#link Thread#stop()} is inherently unsafe, the assumption is that the thread to kill does not hold any monitors on or
* even references to objects referenced by the rest of the JVM, so it is acceptable to do this.
*
* After calling this method nothing from the thread should be used anymore!
*
* #param thread Thread to stop
*/
#SuppressWarnings("deprecation")
private static void killThread(CallableThread<Boolean> thread) {
thread.stop();
}
private static class CallableThread<V> extends Thread {
private final Callable<V> callable;
private V result = null;
private Exception exception = null;
public CallableThread(Callable<V> callable) {
this.callable = callable;
}
#Override
public void run() {
try {
V result = compute();
setResult(result);
} catch (Exception e) {
exception = e;
} catch (ThreadDeath e) {
cleanup();
}
}
private V compute() throws Exception {
return callable.call();
}
private synchronized void cleanup() {
result = null;
}
private synchronized void setResult(V result) {
this.result = result;
}
public synchronized V getResult() {
return result;
}
public synchronized Exception getException() {
return exception;
}
}
}
EDIT:
Thanks to dawce who pointed me to this solution I have been able to solve my original problem without the need for additional threads. I have posted the code there. Thanks to all who have responded.
You can use Thread.stop() if you determine its the only solution available to you. You may need to shutdown and restart your applicaton to ensure its in a good state.
Note: a Thread can capture and ignore ThreadDeath so stop isn't guarenteed to stop all threads.
An alternative way to stop a thread is to run it in a different process. This can be killed as required. This can still leave resources in an incosistent state (like lock files) but it is less likely and easier to control.
The best solution of course is to fix the code so it doesn't do this in the first place and respects Thread.interrupt() instead.
Instead of using Thread.stop() which is deprecated, use Thread.interrupt() which will stop raise the interrupt flag which can be checked via isInterrupted() or interrupted(), or throws an InterruptedException.
My pattern for building extending the Thread class is like this
class MyThread extends Thread{
private volatile boolean keepRunning = true;
public void run(){
while(keepRunning){
// do my work
}
}
public void killThread(){
keepRunning = false;
this.interrupt();
}
}
I'm not saying my way of handling it is perfect, there may bet better, but this works for me.
If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?
It is up to you to decide if it is "acceptable". All we can do is to advise on whether it is safe. And the answer is that it isn't.
what about the non-obvious monitors and references that it holds?
what about notifies, etc that it would otherwise make?
what about actions that it might otherwise make affecting statics?
The problem is that it is difficult (in most cases) to know for sure that you've considered all of the possible interactions that the thread might have with the rest of the application.
Restarting the application is exactly what I try to avoid ...
It strikes me that that is the real root of your problem; i.e. you've designed a program without taking account of the fact that long-running programs need to be restarted for pragmatic reasons. Especially complicated ones that have potential bugs.
If you specifically design your thread code to not hold locks etc., (yes, and this includes the non-explicit locks. eg. a malloc lock that may be used when changing string sizes), then stop the thread, yes. Polling an 'interrupted' flag is fine, except that it means polling an 'interrupted' flag, ie. overhead during the 99.9999% of the time it is not actually set. This can be an issue with high-performance, tight loops.
If the check can be kept out of an innermost loop and still be checked reasonably frequently, then that is indeed the best way to go.
If the flag cannot be checked often, (eg. because of a tight loop in inaccessible library code), you could set the thread priority to the lowest possible and forget it until it does eventually die.
Another bodge that is occasionally possible is to destroy the data upon which the thread is working in such a way that the library code does exit normally, causes an exception to be raised and so control bubbles out of the opaque library code or causes an 'OnError' handler to be called. If the lib. is operating on a string, splatting the string with nulls is sure to do something. Any exception will do - if you can arrange for an AV/segfault in the thread, then fine, as long as you get control back.