The problem is unrelated to the concept of static member or singleton pattern. The problem is the problem of multithreading, the shared data, more exactly, access to the shared objects, and is solved via the mutual exclusion. You have to understand the essence of thread synchronization:
Mutual exclusion — Wikipedia, the free encyclopedia[
^],
Critical section — Wikipedia, the free encyclopedia[
^],
Synchronization (computer science) — Wikipedia, the free encyclopedia[
^],
Race condition — Wikipedia, the free encyclopedia[
^].
Solution 1 gives you an example of mutex use.
But your confusion stems from the lack of clear understanding what you are doing. First of all, you always talk about one or another class performing one or another action on the data. Classes are essentially irrelevant here; you should think of
instances of classes, objects. If two instances work on the same (shared) objects concurrently, it does not matter if they are of the same class or different classes. However, you didn't mention the threads at all, so it's not clear if you even face the thread synchronization issues at all or not. It's not really clear what "about the same" may possibly mean, but it would be safer to assume you really do something in parallel.
Another problem is: you confuse static members and singletons with shared data.
If the object is shared, it does not matter if it is static member of some class or not. Likewise, it does not matter if singleton pattern is implemented or not. You simply share the reference to the same object in different parts of the code; this is all that matters. Actually, it's important to avoid static data by all means; and singleton, which is better, is also best avoided.
Even without static and without singleton, sharing of objects can be implemented, it this is needed, including the cases when it should be only one in the application runtime; you reach all the same goals related to the use of this object and face the same synchronization problems in case of concurrent use of it. Imagine the scenario: somewhere on the upper place of the execution stack, you create both objects accessing the data, the data class and pass the reference of the data class to both objects. As you need the mutex, you also create it in this code and pass the reference to the same objects. That's all.
And finally, let me note that "god object" is not even a pattern. It's a
bad thing, a well-known
anti-pattern of object-oriented programming. Please see:
God object — Wikipedia, the free encyclopedia[
^],
Anti-pattern — Wikipedia, the free encyclopedia[
^].
—SA