Reputation: 13120
A load of tasks are submitted to my application but it keeps hanging and I track it down to this code:
uk.ac.shef.wit.simmetrics.tokenisers.TokeniserWhitespace.tokenizeToArrayList(TokeniserWhitespace.java:133)
uk.ac.shef.wit.simmetrics.similaritymetrics.CosineSimilarity.getSimilarity(CosineSimilarity.java:142)
com.jthink.songkong.match.Scorer.compareValues(Scorer.java:74)
com.jthink.songkong.match.Scorer.calculateTitle(Scorer.java:704)
com.jthink.songkong.match.Scorer.matchRecordingOrTrackTitle(Scorer.java:652)
com.jthink.songkong.match.Scorer.calculateTrackScoreWithinRelease(Scorer.java:538)
com.jthink.songkong.match.Scorer.scoreMatrix(Scorer.java:396)
com.jthink.songkong.match.Scorer.calculateReleaseScore(Scorer.java:1234)
It is basically an string matching algorithm in a 3rd party library but it does not throw ThreadInterruptedException so does this mean I cannot interrupt it, but is certainly a long running process having run for 30 minutes. I have a reference to the thread monitoring this code but is there any way to stop it.
Of course I am looking to fix the 3rd party library but in the meantime I need a way to stop my application hanging by cancelling these hanging tasks. What makes it worse for me is that I use Hibernate, and a hibernate session is created in this stack and then because this TokeniserWhitespace method never finishes my session (and hence database connection) is never released therefore eventually I ran out of database connections and the application completely hangs.
Upvotes: 0
Views: 96
Reputation: 2562
I would try Thread.interrupt()
as even though the interrupted exception isn't thrown it doesn't necessarily mean that the 3rd party library doesn't handle it correctly in some other way. If that doesn't work then I would consider Thread.stop()
even though it is depricated in the hopes that the library's design can handle sudden termination and doesn't end up in an inconsistent state (due to the transactional nature in which you are using it, I doubt there are many shared objects to get corrupted). Thread.stop()
will cause the event to stop immediately and throw a ThreadDeath
exception no matter what it is doing and it was deprecated by Sun due to the chance of leaving shared objects in an unknown and inconsistent state.
Upvotes: 1
Reputation: 18148
You can can use the Akka library to wrap the problematic code - this will let you kill and restart the code if it hangs.
import scala.concurrent.Future;
public interface ProblemCode {
public Future<String> stringMatch(String string);
}
public class ProblemCodeImpl implements ProblemCode {
public Future<String> stringMatch(String string) {
// implementation
}
}
import akka.actor.ActorSystem;
import akka.actor.TypedActor;
import scala.concurrent.Await;
import scala.concurrent.duration.Duration;
import akka.actor.TypedProps;
public class Controller {
private final ActorSystem system = ActorSystem.create("Name");
private ProblemCode problemCodeActor = getProblemCodeActor();
private ProblemCode getProblemCodeActor() {
return TypedActor.get(system).typedActorOf(new TypedProps<ProblemCodeImpl>(ProblemCode.class, ProblemCodeImpl.class));
}
public String controllerStringMatch(String string) {
while(true) {
try {
// wait for a Future to return a String
return Await.result(problemCodeActor.stringMatch(string), Duration.create(5000, TimeUnit.MILLISECONDS));
} catch (TimeoutException e) {
// Await timed out, so stop the actor and create a new one
TypedActor.get(system).stop(problemCodeActor);
problemCodeActor = getProblemCodeActor();
}
}
}
}
In other words, the controller calls stringMatch
on the problem code that has been wrapped in an actor; if this times out (5000 milliseconds in my example) you stop and restart the actor and loop through the controller method again.
ProblemCode
will only execute one method at a time (it will enqueue subsequent invocations), so if you want to concurrently execute stringMatch
you'll need to create multiple actors and create a router out of them / place them in a queue / etc.
Upvotes: 1