org.curjent.agent
Annotation Type Reentrant


@Documented
@Target(value=METHOD)
@Retention(value=RUNTIME)
public @interface Reentrant

Specifies that a synchronous call can be executed within the context of an existing agent call without blocking. This is best illustrated with an example:

 interface Printer {
     void print(String text);
     int getCount();
     void mark(Runnable runnable);
 }
 
 class PrinterTask {
     private int count = 0;
 
     void print(String text) {
         System.out.println(text);
         count++;
     }
     
     @Reentrant
     int getCount() {
         return count;
     }
     
     @Marker
     void mark(Runnable runnable) {
         runnable.run();
     }
 }
 
 class PrinterTest {
     void run() {
         final Printer printer = Agent.newInstance(Printer.class, new PrinterTask());
         for (int i = 0; i < 3; i++) {
             printer.print("Print test #" + i);
         }
         printer.mark(new Runnable(){
            public void run() {
                System.out.println("Finished: count=" + printer.getCount());
            }
         });
     }
 }
 
The task's mark method calls the test's runnable object which in turn calls the agent's getCount method. This would deadlock without the Reentrant annotation. The task's mark method would wait indefinitely for the runnable's synchronous call to getCount to return. But the agent would not execute the getCount call until the mark call has finished.

The Reentrant annotation tells the agent to call the task's getCount method immediately instead of queuing it. This annotation only applies to synchronous calls made to the same agent within an existing call; otherwise, the call is queued normally and the caller waits as usual. This implies reentrant agent calls are always executed within the same thread context, and so no thread synchronization is required of the task. Furthermore, in the case of agents with multiple tasks, the agent executes reentrant calls using the same task.

Call state listeners (see CallStateListener) can only rely on Reentrant call semantics within the context of an executing task, such as when a call transitions to CallState.EXECUTING.



Copyright 2009-2011 Tom Landon
Apache License 2.0