Safe objective multiplayer game state with multiple threads
You have described your options well enough. Probably you need to combine both approaches.

Ensure that you have as little shared state as possible.
Use queue for modifications to whatever shared state remains.
I'm building a multiplayer card game with Python, gevent and django-socketio and I'm wondering about the best way to maintain state on things, bearing in mind that there'll be multiple clients connecting at once and doing things.
I'm using Redis as a datastore for the in game bits, with light object models on top (Redisco at the mo).
I'm concerned about defending against race conditions and therefore keeping the game state safe and consistent with so many clients trying to do things at once.  I'm thinking that my main options are:
(1) - Ensure that all operations are safe with more that one client doing things at once (eg, a player can only interact with certain properties of their own player model, and there's some objective game state via another thread or something which does anything else.)
(2) - Use a queue with some global lock to ensure client operations all happen in a certain guaranteed order, and one finishes before the next one starts.
I'm using Python, Django, django-socketio, gevent, but think this applies more broadly.
Is this the "threadsafe" thing that people refer to?
I guess in theory I think I prefer the idea of (1), and I think that I can ensure safe operations by just modifying a single Redis key at a time, or safe sets of atomic operations, but I guess I'd either need to throw away the Redisco models or be very careful about understanding when things get saved and written.  I think that's fine for just a couple of us working on things but might be dangerous longer term with more people in the codebase.
Thanks!