Az EJB 3.1 megjelenése számos újítást és egyszerűsítést hozott a rendszerbe, a fejlesztők, mint ahogy a 2.x-ről 3.0-ra váltáskor is, igyekeztek még kényelmesebbé tenni az enterprise alkalmazások készítését. Mivel mi Glassfish alkalmazás-szervert használunk, és a kiadást követő napokban kezdtünk bele egy új projektbe, úgy határoztunk, hogy a friss és ropogós EJB-t használjuk (eddig nem bántuk meg) az implementáláshoz. Az új EJB-t tanulmányozva szembeötlött egy lehetőség, ami mellett nem tudtam szó nélkül elmenni. Úgy néz ki, hogy nem csak nekem jutott eszembe, hogy az alkalmazást, amit fejlesztek párhuzamosítsam, hanem az EJB fejlesztőinek is, ezért megalkották az aszinkron EJB hívás fogalmát. A dolog igen egyszerű, a hagyományokhoz híven @Annotációval kell megjelölni azokat a SessionBean metódusokat, amiket nem a hagyományos módon szeretnénk kiajánlani.
package sample;
import javax.ejb.Asynchronous;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
@LocalBean
@Stateless
public class TestBean {
@Asynchronous
public void asyncMethod() {
//some functionality
}
}
A metódus meghívása a megszokott módon történik, viszont az abban elhelyezett utasítások egy új szálon fognak futni. Ez eddig egyszerű, de mi történik, ha szeretnénk, hogy a hívás valamilyen visszatérési értéket is prezentáljon? Ezt úgy tudjuk megtenni, hogy visszatérési értékként a
java.util.concurrent.Future<V> interfészt jelöljük meg, és annak valamely implementációját adjuk vissza.
package sample;
import java.util.concurrent.Future;
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
@LocalBean
@Stateless
public class TestBean {
@Asynchronous
public Future<String> asyncMethod() {
try { Thread.sleep(1000);
} catch (Exception ex) {}
return new AsyncResult<String>("finish");
}
}
A dolog érdekessége a hívó oldalon történik, hiszen valahogy kezelni kell tudni, hogy az aszinkron hívás éppen milyen állapotban van.
Future<String> asyncResponse = testBean.asyncMethod();
//some functionality
while (!asyncResponse.isDone()) {
try { Thread.sleep(100);
} catch (Exception ex) {}
}
if (!asyncResponse.isCancelled()) {
try {
String response = asyncResponse.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {}
}
Láthatjuk mi módon tudjuk "összeszinkronizálni" a hívásokat a szülő szálban. Természetesen meg is lehet szakítani a kérést, a Future cancel metódusával, illetve a rendelkezésünkre állnak a hagyományos Thread notify, notifyAll, és wait metódusai.