Hi, this actually boils down to a strong case of read the manual and one 
surprising effect.

The executive summary: From the Java SE 8 docs description for Thread/sleep:

Throws:IllegalArgumentException 
<https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalArgumentException.html>
 - 
if the value of millis is negativeInterruptedException 
<https://docs.oracle.com/javase/8/docs/api/java/lang/InterruptedException.html> 
- 
if any thread has interrupted the current thread. The *interrupted status* of 
the current thread is cleared when this exception is thrown.

The key to my misunderstanding is right there is the InterruptedException 
doc - the interrupted status is cleared by Thread/sleep.

The remaining surprise is that the future-cancel call actually returns true 
for all the cases (which is different from what I originally wrote).  Check 
out the below examples.

Example 1 - just a normal future with no try/catch
user> (defn test-interrupt-status-1 [init-v]
  (let [n (atom init-v)]
    [n
     (future (while (not (Thread/interrupted))
               (swap! n inc)))]))
#'user/test-interrupt-status-1
user> (def test-1 (test-interrupt-status-1 10))
#'user/test-1
user> (future-cancel (test-1 1))
true
user> (future-cancelled? (test-1 1))
true
user> @(test-1 0)
43202690
user> @(test-1 0)
43202690

Example 2 - a future that contains a try/catch but doesn't have any sleep 
included
Notice that future-cancel works fine even with the try/catch - the atom 
isn't updated
after the future-cancel is called on the future.
user> (defn test-interrupt-status-2 [init-v]
  (let [n (atom init-v)]
    [n
     (future (while (not (Thread/interrupted))
               (try
                 (swap! n inc)
                 (catch Exception e (println (str "Exception:\t" e 
"\nisInterrupted:\t" (.isInterrupted (Thread/currentThread))))))))]))
#'user/test-interrupt-status-2
user> (def test-2 (test-interrupt-status-2 10))
#'user/test-2
user> (future-cancel (test-2 1))
true
user> (future-cancelled? (test-2 1))
true
user> @(test-2 0)
44066815
user> @(test-2 0)
44066815

Example 3 - now we have a future which includes a try/catch AND A 
Thread/sleep
Calling future-cancel returns true (!!) and we see that the Thread/sleep
has cleared the interrupt status of the thread (e.g., the .isInterrupted is 
false
for the thread).  What is interesting here is that future-cancelled? 
returns true
but the thread is actually still happily running because the interrupt 
status was 
reset.  I'm not sure what I think about this - I hate surprises, but the 
docs are pretty
clear on what is happening here.  
user> (defn test-interrupt-status-3 [init-v]
  (let [n (atom init-v)]
    [n
     (future (while (not (Thread/interrupted))
               (try
                 (Thread/sleep 10000)
                 (swap! n inc)
                 (catch Exception e (println (str "Exception:\t" e 
"\nisInterrupted:\t" (.isInterrupted (Thread/currentThread))))))))]))
#'user/test-interrupt-status-3
user> (def test-3 (test-interrupt-status-3 10))
#'user/test-3
user> (future-cancel (test-3 1))
trueException: java.lang.InterruptedException: sleep interrupted
isInterrupted: false
user> (future-cancelled? (test-3 1))
true
user> @(test-3 0)
12
user> @(test-3 0)
13
user> (future-cancel (test-3 1))
false
user> (future-cancelled? (test-3 1))
true


On Thursday, April 28, 2016 at 11:48:29 AM UTC-4, Tom Bodenheimer wrote:
>
> Hi all,
>
> I have recently been playing with futures and have stumbled on the 
> following situation.
>
> (defn test-f1 [initial-v]
>   (let [n (atom initial-v)]
>     [n
>      (future (while (not (Thread/interrupted))
>                (Thread/sleep 5000)
>                (swap! n inc)
>                (println @n)))]))
>
> (def t1 (test-f1 11))
>
> This works as expected.  I see the println outputs, can @(t1 0) and 
> (future-cancel (t1 1)) returns true.
>
> Then I have:
>
> (defn test-f2 [initial-v]
>   (let [n (atom initial-v)]
>     [n
>      (future (while (not (Thread/interrupted))
>                (try
>                  (Thread/sleep 5000)
>                  (swap! n inc)
>                  (println @n)
>                  (catch Exception e (println "whoops")))))]))
>
> (def t2 (test -f2 11))
>
> The same except now my while has a (try ... (catch Exception e ...). 
>  However, now (future-cancel (t2 1)) returns false and the future cannot be 
> cancelled - I also see the "whoops" at the REPL.  Seeing that "whoops" made 
> me wonder if the interrupt that would shutdown the thread is raising an 
> exception that is being caught by my (try .... (catch ...)) block, thus 
> never interrupting the thread. 
>
> I made a change to throw the exception again:
>
> (defn test-f3 [initial-v]
>   (let [n (atom initial-v)]
>     [n
>      (future (while (not (Thread/interrupted))
>                (try
>                  (Thread/sleep 5000)
>                  (swap! n inc)
>                  (println @n)
>                  (catch Exception e (do (println "whoops") (throw 
> e))))))])) 
>
> and the behavior now matches that of test-f1.
>
> I think I'm just not clear on some fundamental aspect of how 
> future-cancel, try/catch, and the underlying java are actually working here.
>
> It seems *very* weird to me that after future-cancel cancels the future, 
> that the (try . . . (catch . . .)) would ever be invoked in the body of the 
> while loop.  Yet, clearly the interrupt is being handled in the (try . . . 
> (catch . . . )).  It also seems *very* weird that even in this case, that 
> the next time we get back to (while (not (Thread/interrupted)) that 
> (not(Thread/interrupted)) would be true . . . I guess the exception sets 
> the interrupt status for the thread.  When exception gets caught in my (try 
> . . . (catch . . .)), the interrupt status is never set?
>
> Thanks for any clarification.
>  
>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to