Author: andy
Date: Thu Apr 18 20:59:24 2013
New Revision: 1469570
URL: http://svn.apache.org/r1469570
Log:
Synchronize operations.
Protect against cancel vs call back being called.
Modified:
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java
Modified:
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
URL:
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java?rev=1469570&r1=1469569&r2=1469570&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
(original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/AlarmClock.java
Thu Apr 18 20:59:24 2013
@@ -23,11 +23,13 @@ import java.util.Set ;
import java.util.Timer ;
/** An AlarmClock is an object that will make a call back at a preset time.
- * It addes to java.util.Timer by having an active Timer (and its thread)
- * only when callbacks are outstanding. The Timer's thread can stop the JVM
exiting.
+ * It adds tracking to a java.util.Time and also by having
+ * an active Timer (and its thread) only when callbacks are outstanding.
+ * The Timer's thread can stop the JVM exiting.
*/
public class AlarmClock
{
+ // ** Switch to ScheduledThreadPoolExecutor
// Our callback-later instance
// Wrap a TimerTask so that the TimerTask.cancel operation can not be
called
// directly by the app. We need to go via AlarmClock tracking of callbacks
so
@@ -89,13 +91,32 @@ public class AlarmClock
if ( timer == null )
// Nothing outstanding.
return ;
- outstanding.remove(pingback) ;
+ // Calls remove$
+ pingback.cancel();
// Throw timer, and it's thread, away if no outstanding pingbacks.
- // This helps apps exit properly (daemon threads don't always seem to
be as clean as porimised)
- // but may be troublesome in large systems. May reconsider.
+ // This helps apps exit properly but may be troublesome in large
systems.
+ // May reconsider.
if ( clearTimer && getCount() == 0 )
{
- timer.cancel();
+ release() ;
+ }
+ }
+
+ /*package*/ void remove$(Pingback<?> pingback)
+ {
+ outstanding.remove(pingback) ;
+ }
+
+ public synchronized void release()
+ {
+ release$() ;
+ }
+
+ private void release$()
+ {
+ if ( timer != null )
+ {
+ timer.cancel() ;
timer = null ;
}
}
@@ -106,6 +127,5 @@ public class AlarmClock
timer = new Timer(true) ;
return timer ;
}
-
- public long timeStart = System.currentTimeMillis() ;
-}
+}
+
Modified:
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java
URL:
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java?rev=1469570&r1=1469569&r2=1469570&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java
(original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/lib/Pingback.java
Thu Apr 18 20:59:24 2013
@@ -20,23 +20,39 @@ package org.apache.jena.atlas.lib;
import java.util.TimerTask ;
+/** Wrapper around a TimerTask, adding a callback with argument. */
public class Pingback<T>
{
+ private final AlarmClock alarmClock ;
final TimerTask timerTask ;
final Callback<T> callback ;
final T arg ;
+ // As good as an AtomicBoolean which is implemented as a volative int for
get/set.
+ private volatile boolean cancelled = false ;
Pingback(final AlarmClock alarmClock, final Callback<T> callback, T
argument)
{
+ this.alarmClock = alarmClock ;
this.callback = callback ;
this.arg = argument ;
this.timerTask = new TimerTask() {
@Override
public void run()
{
+ if ( cancelled )
+ return ;
+ cancelled = true ;
+ alarmClock.remove$(Pingback.this) ;
callback.proc(arg) ;
- alarmClock.cancel(Pingback.this) ;
}
} ;
}
+
+ void cancel()
+ {
+ timerTask.cancel() ;
+ cancelled = true ;
+ alarmClock.remove$(this) ;
+ }
}
+
Modified:
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java
URL:
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java?rev=1469570&r1=1469569&r2=1469570&view=diff
==============================================================================
---
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java
(original)
+++
jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/lib/TestAlarmClock.java
Thu Apr 18 20:59:24 2013
@@ -19,6 +19,9 @@
package org.apache.jena.atlas.lib;
import static org.apache.jena.atlas.lib.Lib.sleep ;
+
+import java.util.concurrent.atomic.AtomicInteger ;
+
import org.apache.jena.atlas.junit.BaseTest ;
import org.apache.jena.atlas.lib.AlarmClock ;
import org.apache.jena.atlas.lib.Callback ;
@@ -27,8 +30,20 @@ import org.junit.Test ;
public class TestAlarmClock extends BaseTest
{
- Callback<?> callback = new Callback<Object>() { @Override
- public void proc(Object arg) {} } ;
+ static class CallbackTest implements Callback<Object>
+ {
+ AtomicInteger count = new AtomicInteger(0) ;
+
+ public int getCount() { return count.get() ; }
+
+ @Override
+ public void proc(Object arg)
+ {
+ count.getAndIncrement() ;
+ }
+ } ;
+
+ CallbackTest callback = new CallbackTest() ;
@Test public void alarm_01()
{
@@ -39,6 +54,8 @@ public class TestAlarmClock extends Base
assertEquals(1, alarmClock.getCount()) ;
alarmClock.cancel(ping) ;
assertEquals(0, alarmClock.getCount()) ;
+ assertEquals(0, callback.getCount()) ;
+ alarmClock.release() ;
}
@Test public void alarm_02()
@@ -49,10 +66,12 @@ public class TestAlarmClock extends Base
Pingback<?> ping = alarmClock.add(callback, 10) ;
sleep(100) ;
assertEquals(0, alarmClock.getCount()) ;
+ assertEquals(1, callback.getCount()) ;
// try to cancel anyway.
- alarmClock.cancel(ping) ;
+ ping.cancel() ;
assertEquals(0, alarmClock.getCount()) ;
+ alarmClock.release() ;
}
@Test public void alarm_03()
@@ -65,25 +84,44 @@ public class TestAlarmClock extends Base
sleep(200) ;
// ping1 went off.
assertEquals(1, alarmClock.getCount()) ;
- alarmClock.cancel(ping1) ;
+ assertEquals(1, callback.getCount()) ;
+ ping1.cancel() ;
+
assertEquals(1, alarmClock.getCount()) ;
alarmClock.cancel(ping2) ;
assertEquals(0, alarmClock.getCount()) ;
+ assertEquals(1, callback.getCount()) ;
+ alarmClock.release() ;
}
@Test public void alarm_04()
{
AlarmClock alarmClock = new AlarmClock() ;
assertEquals(0, alarmClock.getCount()) ;
+ Pingback<?> ping1 = alarmClock.add(callback, 10) ;
+ Pingback<?> ping2 = alarmClock.add(callback, 20) ;
+ assertEquals(2, alarmClock.getCount()) ;
+ sleep(200) ;
+ // ping1 went off. ping2 went off.
+ assertEquals(0, alarmClock.getCount()) ;
+ assertEquals(2, callback.getCount()) ;
+ alarmClock.release() ;
+ }
+
+ @Test public void alarm_05()
+ {
+ AlarmClock alarmClock = new AlarmClock() ;
+ assertEquals(0, alarmClock.getCount()) ;
Pingback<?> ping1 = alarmClock.add(callback, 100) ;
assertEquals(1, alarmClock.getCount()) ;
alarmClock.reset(ping1, 2000) ;
assertEquals(1, alarmClock.getCount()) ;
sleep(100) ;
assertEquals(1, alarmClock.getCount()) ;
+ alarmClock.release() ;
}
- @Test public void alarm_05()
+ @Test public void alarm_06()
{
AlarmClock alarmClock = new AlarmClock() ;
assertEquals(0, alarmClock.getCount()) ;
@@ -92,8 +130,10 @@ public class TestAlarmClock extends Base
assertEquals(2, alarmClock.getCount()) ;
alarmClock.reset(ping1, 2000) ;
assertEquals(2, alarmClock.getCount()) ;
- sleep(200) ; // ping2 goes off.
+ sleep(200) ; // just ping2 goes off.
+ assertEquals(1, callback.getCount()) ;
assertEquals(1, alarmClock.getCount()) ;
+ alarmClock.release() ;
}
}