Replace OrientationRestorer TimerTask usage with ScheduledExecutor 20/1320/2
authorjsimomaa <jani.simomaa@gmail.com>
Thu, 14 Dec 2017 06:16:51 +0000 (08:16 +0200)
committerJani Simomaa <jani.simomaa@semantum.fi>
Thu, 14 Dec 2017 06:17:18 +0000 (08:17 +0200)
Timer can exhaust the system with TimerTask-runnables that are queued up
e.g. during computer hibernate and sleep. According to documentation:

If an execution is delayed for any reason (such as garbage collection or
other background activity), two or more executions will occur in rapid
succession to "catch up." In the long run, the frequency of execution
will be exactly the reciprocal of the specified period

With heavy tasks this is very bad

refs #7682

Change-Id: I5a097c8bc5e1ea2a5abe30905b2a46fa8b8386f8

bundles/org.simantics.g2d/src/org/simantics/g2d/participant/OrientationRestorer.java

index 02cd89d9caa9105525122063cd50bbfe777b7003..f2a420b1221910c1f54e1dba891ad8417bfcc449 100644 (file)
@@ -13,8 +13,9 @@ package org.simantics.g2d.participant;
 
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
-import java.util.Timer;
-import java.util.TimerTask;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 import org.simantics.g2d.canvas.Hints;
 import org.simantics.g2d.canvas.ICanvasContext;
@@ -22,8 +23,8 @@ import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
 import org.simantics.g2d.canvas.impl.HintReflection.HintListener;
 import org.simantics.utils.datastructures.disposable.DisposeState;
-import org.simantics.utils.datastructures.hints.IHintObservable;
 import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.datastructures.hints.IHintObservable;
 import org.simantics.utils.threads.IThreadWorkQueue;
 
 /**
@@ -44,10 +45,10 @@ public class OrientationRestorer extends AbstractCanvasParticipant {
     long                    lastTrigger;
     Point2D                 centerPoint        = new Point2D.Double();
 
-    transient Timer         timer              = new Timer("Rotate restore");
+    transient ScheduledExecutorService         timer              = Executors.newSingleThreadScheduledExecutor();
     transient boolean       checkRotatePending = false;
 
-    TimerTask               task               = new TimerTask() {
+    Runnable               task               = new Runnable() {
         @Override
         public void run() {
             ICanvasContext ctx = getContext();
@@ -70,16 +71,24 @@ public class OrientationRestorer extends AbstractCanvasParticipant {
 
     @Override
     public void removedFromContext(ICanvasContext ctx) {
-        timer.cancel();
+        timer.shutdown();
+        try {
+            if (!timer.awaitTermination(1, TimeUnit.SECONDS)) {
+                timer.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            // Ignore
+        }
         super.removedFromContext(ctx);
     }
 
     @Override
     public void addedToContext(ICanvasContext ctx) {
         super.addedToContext(ctx);
-        long delay = 1000 / 25;
+//        long delay = 1000 / 25; this sounds quite frequent
+        long delay = 1000 / 10;
         lastTrigger = System.currentTimeMillis();
-        timer.scheduleAtFixedRate(task, delay, delay);
+        timer.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);
     }
 
     @HintListener(Class = Hints.class, Field = "KEY_CANVAS_BOUNDS")