Thousands of things probably isn't that big of deal. As you note, even older games like SimTower could do this pretty reasonably. Consequently the first thing I'd suggest you do is the simple, straightforward option:
foreach(Thing t in AllOfTheThings) {
t.Simulate(elapsedTime);
}
Once you've done that, if your game still runs acceptably, then you're done. If it doesn't, or if it starts to slow down, profile the game to make sure you're actually bottlenecking on entity simulation code. If you aren't, solve that problem instead.
But after all that, if you are bottlenecking on entity simulation, there are some techniques you can employ.
You can adjust the tick rate of entities. Instead of ticking all of them every frame, tick half of them one frame and half of them the other (for example, odd numbered entities on odd frames, even numbered ones on even frames). The delay in any individual entity update will not likely be noticed by the player, but you will have reduced your per-frame workload by half.
Similar to the above, you can tick entities differently based on how far away they are from the player's current camera focus. This is common in open-world games like Skyrim, which always simulates active NPCs, but does so far less frequently for NPCs that are far away from the player because the player can't see or interact with them.
The above two methods are ways of reducing the level of detail in the tick rate; you could instead reduce level of detail in the simulation. If an entity is too far away from the player's focal point, you can drop some highly-detailed aspects of their update to save time. You may not need to accurately simulate their pathfinding, for example. Instead, switch them to a coarser simulation that just makes sure their basic needs are met: Should I sleep? Teleport to bed instead of bothering to try to walk there. Should I shower? Teleport to the bathroom. Pathfinding can be expensive so this can save some time.
If entities cannot affect eachother during their simulation, or you can identify isolated groups of entities that will not affect entities outside of that group during simulation, you can offload the processing of those entities or groups to worker threads, running them in parallel.
Ensure your entities and the update system they use are designed to take advantage of cache coherency in their data. It can be a huge performance win.
All of these methods have pros and cons, and must be adapted to your specific scenario and the needs of your game. You may need to employ all of these methods, or maybe none, or maybe you can select a few that work best for the profiling data you've gathered.
One last piece of advice is to start your simulation relatively simple. You may be surprised as how complex simple simulations can end up looking in practice once you introduce sufficient scale and some basic randomization. You may be surprised to discover much of the "complicated" simulation you think is going on in SimTower and similar games really isn't all that complicated and ends up being quite trivial for a modern machine to perform at scale.