Java SE API Concurrency problem
Posted: 11 Sep 2012, 12:52
Hi!
I'm currently doing quick tests and demos with SFS2x Java API.
I'm using Swing UI for it.
I can post all the code here, but I'm using a quick example to show the problem...
I have the classe conn.Login.
It's implements the IEventListener SFS2x class for handling events from the client API.
Something like this:
The first problem is:
When I receive the login, I want to free the class conn.Login.
The best time to do it is when the login is successful. So in the Controller's of SwingUI class I put something like it:
myAppController is the class that bind SwingUI (create view) and also has the conn.Login instance.
The freeLogin() methods is going to call conn.Login::free() that will removeEventListeners from clientAPI.
That happens in the same call of dispatch() that is using the event listeners list in the SFS2x Client API.
Then occurs the Concurrency Problem:
How I can remove the eventListeners of Login (aka free the conn.Login class) after the event login success?
The same problem will happen with ROOM_JOIN::
There are a "Global Lobby Room" that I enter by default
Inside it, I can stay there or go to 5 rooms I can choose (North America, South America, Europe, Australia, Asia)
The first ROOM_JOIN event. I need to remove it from the conn.Lobby class after I enter this room "Global Lobby Room"., so I can enable and use the ROOM_JOIN event in the class conn.CountryRoom to enter the "South America" room.
But will fall in Concurrency problem, like the LOGIN. Because I'm calling the removeEventListener(SFSEvent.ROOM_JOIN...) when the dispatch happens.
Any clues?
I will need one more Thread and queue to remove the handlers?
There's another way?
Because I can receive a private message, per example, at same moment that the other Thread is removing the eventListener.
Thanks in advance!
R.
I'm currently doing quick tests and demos with SFS2x Java API.
I'm using Swing UI for it.
I can post all the code here, but I'm using a quick example to show the problem...
I have the classe conn.Login.
It's implements the IEventListener SFS2x class for handling events from the client API.
Something like this:
Code: Select all
package conn;
public class Login implements IEventListener {
private SmartFox clientAPI;
public Login(SmartFox client) {
clientAPI = client;
}
@Override
public void dispatch(final BaseEvent event) throws SFSException {
String eventType = event.getType();
if(eventType.equals(SFSEvent.LOGIN)) {
User user = (User)event.getArguments().get("user");
ISFSObject data = (ISFSObject)event.getArguments().get("data");
// Here the login success will be notified to UI interface, so the SwingUI can show that Login is done.
// The method that will be called is onLoginSuccess().
}
else if(eventType.equals(SFSEvent.LOGIN_ERROR)) {
String errorMessage = (String)event.getArguments().get("errorMessage");
short errorCode = (Short)event.getArguments().get("errorCode");
// Here the login error will be notified to UI interface, so the SwingUI can show that Login had errors..
}
else {}
}
public final void init() {
clientAPI.addEventListener(SFSEvent.LOGIN, this);
clientAPI.addEventListener(SFSEvent.LOGIN_ERROR, this);
}
public final void free() {
clientAPI.removeEventListener(SFSEvent.LOGIN, this);
clientAPI.removeEventListener(SFSEvent.LOGIN_ERROR, this);
}
}
The first problem is:
When I receive the login, I want to free the class conn.Login.
The best time to do it is when the login is successful. So in the Controller's of SwingUI class I put something like it:
Code: Select all
// Method called from the conn.Login::dispatch(SFSEvent.LOGIN).
public final void onLoginSuccess() {
myAppController.freeLogin();
}
myAppController is the class that bind SwingUI (create view) and also has the conn.Login instance.
The freeLogin() methods is going to call conn.Login::free() that will removeEventListeners from clientAPI.
That happens in the same call of dispatch() that is using the event listeners list in the SFS2x Client API.
Then occurs the Concurrency Problem:
Code: Select all
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at sfs2x.client.core.EventDispatcher.dispatchEvent(EventDispatcher.java:51)
at sfs2x.client.SmartFox.dispatchEvent(SmartFox.java:1265)
at sfs2x.client.controllers.system.ResLogout.handleResponse(ResLogout.java:26)
at sfs2x.client.controllers.SystemController.handleMessage(SystemController.java:104)
at sfs2x.client.core.SFSProtocolCodec.dispatchRequest(SFSProtocolCodec.java:144)
at sfs2x.client.core.SFSProtocolCodec.onPacketRead(SFSProtocolCodec.java:50)
at sfs2x.client.core.SFSIOHandler.handlePacketData(SFSIOHandler.java:281)
at sfs2x.client.core.SFSIOHandler.onDataRead(SFSIOHandler.java:130)
at sfs2x.client.bitswarm.BitSwarmClient.onSocketData(BitSwarmClient.java:354)
at sfs2x.client.bitswarm.BitSwarmClient.access$2(BitSwarmClient.java:348)
at sfs2x.client.bitswarm.BitSwarmClient$3.dispatch(BitSwarmClient.java:105)
at sfs2x.client.core.EventDispatcher.dispatchEvent(EventDispatcher.java:52)
at sfs2x.client.core.sockets.TCPSocketLayer.callOnData(TCPSocketLayer.java:144)
at sfs2x.client.core.sockets.TCPSocketLayer.handleBinaryData(TCPSocketLayer.java:138)
at sfs2x.client.core.sockets.TCPSocketLayer.access$6(TCPSocketLayer.java:137)
at sfs2x.client.core.sockets.TCPSocketLayer$NettyIOHandler.messageReceived(TCPSocketLayer.java:273)
at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:100)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:545)
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:540)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:350)
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:281)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:201)
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
at org.jboss.netty.util.internal.IoWorkerRunnable.run(IoWorkerRunnable.java:46)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
How I can remove the eventListeners of Login (aka free the conn.Login class) after the event login success?
The same problem will happen with ROOM_JOIN::
There are a "Global Lobby Room" that I enter by default
Inside it, I can stay there or go to 5 rooms I can choose (North America, South America, Europe, Australia, Asia)
The first ROOM_JOIN event. I need to remove it from the conn.Lobby class after I enter this room "Global Lobby Room"., so I can enable and use the ROOM_JOIN event in the class conn.CountryRoom to enter the "South America" room.
But will fall in Concurrency problem, like the LOGIN. Because I'm calling the removeEventListener(SFSEvent.ROOM_JOIN...) when the dispatch happens.
Any clues?
I will need one more Thread and queue to remove the handlers?
There's another way?
Because I can receive a private message, per example, at same moment that the other Thread is removing the eventListener.
Thanks in advance!
R.