Hi Joe,
I'm definitely sympathetic with the scenario, and as you point out the
developer can schedule the 'external' thread by hand, even if its not ideal.
However, I suspect that coming up with a good, general solution to this
will require quite some thought, and from my perspective we're just not
in a position to design and implement new mechanisms like this at this
late point in the spec.
I know we have been accommodating smaller API changes up until this
week, but they were for pre-existing features like programmatic
deployment, and relatively well-understood areas like endpoint instance
creation. Both of which we've had time to chew on a few occasions
before. Most of our time since the new year has been spent, very
profitably I think, on clarifying the features we already have.
So I would like to punt on this for this version, and get it on the list
for the next version.
Thanks,
- Danny
On 2/26/13 12:59 PM, Joe Walnes wrote:
> In section 5.1.Threading considerations:
>
> "In all cases, the implementation must not invoke an endpoint instance
> with more than one thread per peer at a time. ... This guarantees that
> a websocket endpoint instance is never called by more than one
> container thread at a time per peer."
>
> A scenario I run into a lot is:
> * An endpoint needs to call into another library, which will run
> something in the background on another thread and then run a callback
> when complete. This might be a long running third party library, or
> maybe a java.util.Timer.
> * The callback needs to interact with state belonging to the endpoint
> instance (e.g. send a message, or change an in memory data-structure).
> * Because the callback has not been initiated by the container, we
> have no guarantee that the container is not calling other methods on
> the endpoint at the same time that the callback is invoked. Race
> conditions ahoy.
>
> It is possible to work around this by implementing locks in the
> endpoint. But this puts lots of responsibility on the end user, is
> messy and very easy to get wrong.
>
> I propose we add a mechanism to allow user code running in other
> threads to schedule some code to be run by a container thread that
> follows the same semantics as the other endpoint methods invoked by
> the container - i.e. only one at a time per instance endpoint.
>
> To do this, we could make Session implement
> java.util.concurrent.Executor. Any Runnable passed to it will be run
> by the container in a safe way.
>
> Example:
>
> class MyEndpoint {
>
> @OnMessage
> public void onMsg(String msg, final Session session) {
>
> Runnable callback = new Runnable() {
> public void run() {
> // 4. ok, we're back on the Endpoint thread now.
> // we can safely use interact with other objects
> session.getRemoteBasic().sendString("Hello! Remember me.");
> }
> }
>
> // 1. schedule something to happen in the future, without blocking.
> new Timer().schedule(new TimerTask() {
> public void run() {
> // 3. sometime later, the Timer library calls this on its
> // own unsafe thread.
> session.execute(callback); // thunk to container thread
> }
> }, 10000);
> // 2. return immediately.
>
> }
>
> }
>
> Thoughts?
>
> -Joe
--
<http://www.oracle.com> *Danny Coward *
Java EE
Oracle Corporation