When a jrebel agent (v 6.2.5 or later) is attached to the JVM it alters the WildFly EJB interceptors that exists between the EJB pojos and the EJB reference types (call site code). More specifically it:
- Introduces this new method: org.jboss.as.ee.component.ViewService$View.__invoke()
- Modifies existing method: org.jboss.as.ee.component.ViewService$View.invoke() (By introducing the synchronized modifier)
When jrebel has done this to EJB @Singleton components in WildFly …and when their methods are invoked concurrently we can end up in a deadlocked situation.
Try it !
The arquillian test below can cause such deadlocks. To make it deadlock, all you have to do is to add the -javaagent:/path/to/jrebel.jar argument in standalone.conf (or in Eclipse: in the program launcher). The example will only deadlock when the jrebel agent is associated with the jvm.
@SuppressWarnings("nls")
@RunWith(Arquillian.class)
public class DeadLockArquillianTest {
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class) //
.addClass(FriendOne.class)//
.addClass(FriendTwo.class);
}
@EJB
FriendOne one;
@EJB
FriendTwo two;
@Test
public void goNutz() throws Exception {
// run with
// -javaagent:/path/to/jrebel/jrebel.jar
// to deadlock the threads....
int nThreads = 2;
ExecutorService e = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < nThreads; i++) {
final String label = String.format("Thread %02d", i);
e.submit(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100; j++) {
if (j % 2 == 0) {
one.sayHello();
} else {
two.sayHello();
}
System.out.format("%s methodcall %3d ...%n", label, j);
}
}
});
}
System.out.println("WAITING");
e.shutdown();
e.awaitTermination(2, TimeUnit.MINUTES);
}
@Startup
@Singleton
@Lock(LockType.READ)
public class FriendOne {
@EJB
FriendTwo otherFriend;
@Lock(LockType.READ)
public String sayHello() {
return "hello" + otherFriend.format("1hello world");
}
@Lock(LockType.READ)
public String format(String input) {
return "FORMATTED by FriendOne TO: " + input;
}
}
@Startup
@Singleton
@Lock(LockType.READ)
public class FriendTwo {
@EJB
FriendOne otherFriend;
@Lock(LockType.READ)
public String sayHello() {
return "hello" + otherFriend.format("2hello world");
}
@Lock(LockType.READ)
public String format(String input) {
return "FORMATTED by FriendTwo TO: " + input;
}
}
Note that the READ locks effectively means that multiple threads may be in the EJB instances at the same time. That is also why the system doesn’t deadlock in the absence of the jrebel agent.
-
This topic was modified 21 hours, 55 minutes ago by
Nicky Mølholm. Reason: formulation