The MC server has basically a single “main” thread and lots of other minor threads.
Almost all events occur on the main thread (except those that don’t) and similarly almost all methods in the API had to be called from the main thread (again except those that didn’t).
In future versions, worlds might be handled on their own thread. Glowstone already does this and there has been suggestions that MC might go that way too.
If we say that calling any API method from inside an event handler is always safe, then we could end up in difficulties when someone tries to alter blocks in one world during an event in a different world.
Alternatively, we could say that inter-world interactions are potentially not thread-safe. For the time being that is over cautious.
Whatever we decide, we should have some kind of annotation to indicate which methods can be called in a thread-safe manner.
In Spout, we went to far down the road of making everything thread-safe and that harmed performance. For Sponge, we can’t change the internal thread model anyway, so that is not an issue.
This could be included into the API by adding a base type of an event for async events.
AsyncEvent extends Event
This means that the event is async. Only thread-safe API methods can be called and methods in the event itself.
@Threadsafe
This is a thread-safe method and can be called at any time.
I think that any calls that interact directly with the MC core would be hard to make “anytime” thread-safe. In Spout we had a “snapshot-lock”. The idea was that if you locked that, you were sure that you wouldn’t update when data needed to be stable (e.g. when sending block updates to the network).
This is as an alternative to submitting a task. You can write a thread and it will sync to the main thread.
Lock apiLock = game.getScheduler().geAPILock();
apiLock.lock();
try {
} finally {
apiLock.unlock();
}
When you lock the api lock lock, your thread would wait until the main thread is ready. On the main thread, at some point in the tick sequence, it would check if any locks were pending. If so, it would release the api-lock and wake up the waiting threads.
This means that if you lock the api lock and then Thread.sleep(…), it is like doing it on the main thread.
If threading is handled at the World level, then there could get .getAPILock(World world) for that world’s API lock. This would allow interworld interactions.