2013-05-11 235 views
0

我在这个最简单的例子中做错了什么? (Glassfish的4.0-B87 + Eclipse的开普勒M6)不能取消@异步调用EJB

Myself.java

package com.example.cancelbug; 

import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 

import javax.annotation.PostConstruct; 
import javax.annotation.PreDestroy; 
import javax.ejb.Singleton; 
import javax.ejb.Startup; 
import javax.inject.Inject; 

@Singleton 
@Startup 
public class Myself { 
    @Inject Other other; 
    private Future <Integer> future; 

    @PostConstruct 
    public void post_construct() { 
    System.out.println("post_construct started"); 
    future = other.ton_of_work(); 
    System.out.println("post_construct ended"); 
    } 

    @PreDestroy 
    public void pre_destroy() { 
    System.out.println("pre_destroy started"); 
    System.out.println("cancel result: " + Boolean.toString(future.cancel(true))); 
    try { 
     System.out.println("future result: " + future.get().toString()); 
    } catch (InterruptedException | ExecutionException e) { 
     System.out.println("future result: interrupted"); 
     Thread.currentThread().interrupt(); 
     System.out.println("thread reinterrupted"); 
    } 
    System.out.println("pre_destroy ended"); 
    } 
} 

Other.java

package com.example.cancelbug; 

import java.util.concurrent.Future; 

import javax.ejb.AsyncResult; 
import javax.ejb.Asynchronous; 
import javax.ejb.Stateless; 

@Stateless 
public class Other { 
    @Asynchronous 
    public Future <Integer> ton_of_work() { 
    System.out.println("other: ton_of_work started"); 
    int i; 
    for (i = 0; i < 10; ++i) { 
     try { 
     System.out.println("other: take a nap"); 
     Thread.sleep(1000L); 
     System.out.println("other: woke up: " + Integer.toString(i)); 
     } catch (InterruptedException e) { 
     System.out.println("other: ton_of_work interrupted"); 
     Thread.currentThread().interrupt(); 
     break; 
     } 
    } 
    System.out.println("other: ton_of_work returning"); 
    return new AsyncResult <Integer>(new Integer(i)); 
    } 
} 

输出

post_construct started 
post_construct ended 
other: ton_of_work started 
other: take a nap 
other: woke up: 0 
other: take a nap 
other: woke up: 1 
other: take a nap 
other: woke up: 2 
other: take a nap 
pre_destroy started 
cancel result: false   <<<<<<< expected true; ton_of_work: interrupted 
other: woke up: 3    <<<<<<< expected no such output 
other: take a nap    <<<<<<< expected no such output 
other: woke up: 4    <<<<<<< expected no such output 
other: take a nap    <<<<<<< expected no such output 
other: woke up: 5    <<<<<<< expected no such output 
other: take a nap    <<<<<<< expected no such output 
other: woke up: 6    <<<<<<< expected no such output 
other: take a nap    <<<<<<< expected no such output 
other: woke up: 7    <<<<<<< expected no such output 
other: take a nap    <<<<<<< expected no such output 
other: woke up: 8    <<<<<<< expected no such output 
other: take a nap    <<<<<<< expected no such output 
other: woke up: 9    <<<<<<< expected no such output 
other: ton_of_work returning 
future result: 10    <<<<<<< expected 2 
pre_destroy ended 

预期输出:

post_construct started 
post_construct ended 
other: ton_of_work started 
other: take a nap 
other: woke up: 0 
other: take a nap 
other: woke up: 1 
other: take a nap 
other: woke up: 2 
other: take a nap 
pre_destroy started 
cancel result: true    <<<<<<< actual false 
other: ton_of_work interrupted <<<<<<< actual missing 
other: ton_of_work returning 
future result: 2    <<<<<<< actual 10 
pre_destroy ended 
+0

注入'@Resource SessionContext session_context;'并调用'session_context.wasCancelCalled()'确实返回true,但它不会中断'sleep'或其他阻塞调用,所以让应用程序逻辑也调查状态不够频繁。 – necromancer 2013-05-11 03:58:25

回答

8

EJB 3.1只提供协作异步中断;也就是说,EJB可以检查客户端是否调用了cancel。即使Future.cancel(true)被调用,也无法获得实际的Thread.interrupt。

有一个开放的EJB规范问题(EJB_SPEC-73)允许实际线程中断。这在EJB 3.2专家组(1,2,3,4, 5,6)上进行了讨论,但讨论最终推迟到下一版本的EJB规范。

+0

感谢您的权威和完整的答案! – necromancer 2013-05-11 20:23:58