diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2014-12-09 12:51:40 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2014-12-09 13:17:03 +0100 |
commit | 6ddde10b4006ece33bc358a391a13e108a35f6fa (patch) | |
tree | 2a1b66691b588c2cb931934133fc911b052ae61b /jurt/com/sun/star/lib/util | |
parent | 4c66ce8ec8f67d3bc2db5c79de68f4bda26d2e60 (diff) |
rhbz#1036877: Join Java AsynchronousFinalizer thread well before exit
AsynchronousFinalizer was originally added as
870a4401c05beec3d31c1f6055a64591edd0a9d9 "INTEGRATION: CWS mtg1: #i57753# Avoid
long-running finalize methods" referring to
<https://issues.apache.org/ooo/show_bug.cgi?id=57753> " Fix JNI-UNO bridge so
that the JVM doesn't run out of memory when a destructor locks the SolarMutex."
It is unclear to me how relevant "If JVMs are getting more mature and should no
longer have problems with long-running finalize methods, this class could be
removed again" really is in practice. After all, advice on hotspot-gc-devel is
to avoid finalize() if possible
(<http://mail.openjdk.java.net/pipermail/hotspot-gc-dev/2014-June/010215.html>
"Re: History of finalizer execution and gc progress?"). So stick with this
approach of home-grown draining for now (where a home-grown approach using
PhantomReferencens would need a dedicated draining thread, too, so would not
have much benefit over the existing code in practice).
Timely termination of AsynchronousFinalizer threads is achieved by using a
dedicated thread per bridge and joining it in the remote bridge's dispose()
resp. the JNI environment's new java_env_dispose.
Change-Id: Idcef2dbf361a1de22f60db73828f59e85711aea7
Diffstat (limited to 'jurt/com/sun/star/lib/util')
-rw-r--r-- | jurt/com/sun/star/lib/util/AsynchronousFinalizer.java | 71 |
1 files changed, 43 insertions, 28 deletions
diff --git a/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java b/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java index 4dcd69a97e1f..71743b25241b 100644 --- a/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java +++ b/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java @@ -35,6 +35,37 @@ import java.util.LinkedList; * long-running finalize methods, this class could be removed again.</p> */ public final class AsynchronousFinalizer { + public AsynchronousFinalizer() { + thread = new Thread("AsynchronousFinalizer") { + @Override + public void run() { + for (;;) { + Job j; + synchronized (queue) { + for (;;) { + if (done) { + return; + } + if (!queue.isEmpty()) { + break; + } + try { + queue.wait(); + } catch (InterruptedException e) { + return; + } + } + j = queue.remove(0); + } + try { + j.run(); + } catch (Throwable e) {} + } + } + }; + thread.start(); + } + /** * Add a job to be executed asynchronously. * @@ -43,7 +74,7 @@ public final class AsynchronousFinalizer { * * @param job represents the body of some finalize method; must not be null. */ - public static void add(Job job) { + public void add(Job job) { synchronized (queue) { boolean first = queue.isEmpty(); queue.add(job); @@ -53,6 +84,14 @@ public final class AsynchronousFinalizer { } } + public void drain() throws InterruptedException { + synchronized (queue) { + done = true; + queue.notify(); + } + thread.join(); + } + /** * An interface to represent bodies of finalize methods. * @@ -65,31 +104,7 @@ public final class AsynchronousFinalizer { void run() throws Throwable; } - private static final LinkedList<Job> queue = new LinkedList<Job>(); - - static { - Thread t = new Thread("AsynchronousFinalizer") { - @Override - public void run() { - for (;;) { - Job j; - synchronized (queue) { - while (queue.isEmpty()) { - try { - queue.wait(); - } catch (InterruptedException e) {} - } - j = queue.remove(0); - } - try { - j.run(); - } catch (Throwable e) {} - } - } - }; - t.setDaemon(true); - t.start(); - } - - private AsynchronousFinalizer() {} + private final LinkedList<Job> queue = new LinkedList<Job>(); + private final Thread thread; + private boolean done = false; } |