Ditto destructors -- you should write your code such that a destructor closing a resource is considered a programming error. assert(FALSE) in a debug build, log it in production, but don't just let such a bug creep silently by. The only exceptions are C++ RAII wrapper classes, which are designed to have magical destructors.
C#'s using(), Python's with statement, Haskell's with* functions -- they're all designed to solve the problem that a generic garbage collector doesn't and shouldn't, which is "I need precise control over the lifetime of this resource allocation". Java doesn't have such a mechanism, but then, Java doesn't have much of anything for a supposedly high-level language. C doesn't have such a mechanism, but that's OK, because it also doesn't have exceptions.
Additionally, programming with threads is much less complicated than the author is making it out to be. Sure, it's hard if you're manually (un)locking mutexes like a damn caveman -- but every major high-level language available today (except, again, Java) provides better abstractions. Some, like Erlang and Haskell, make concurrent and parallel programming especially easy.
Finally, if you can get by with a single-threaded, refcounted, deterministic program -- go ahead. Have fun. The rest of us, here in the real world, have applications more complicated than a high-school midterm to work on. And customers won't pay you if the user interface is sluggish because you were too ignorant to write a proper thread pool.