The key difference however being that finalization of an object is guaranteed when it falls out of scope, and not at the whims of when the garbage collector decides to run.
It would be a nonsensical idea to leave up to the garbage collector releasing an acquired lock on its own time. Such a situation could very easily cause a deadlock, as a program may be waiting on a lock that the garbage collector must release, but while the program is waiting on the lock, no additional garbage is being generated that might trigger a garbage collector run, nor is there any guarantee that even if that run does complete, that the objects you wanted finalized would be.
You do realize you have settings when you want the garbage collector to do its things, yes? As in what you talk about is "lazy" garbage collector, but there are other degrees of when to run. You can set it to be as aggressive immediately after it detects the object is no longer need it, equivalent of "Object.Free" in other languages.
It would be a nonsensical idea to leave up to the garbage collector releasing an acquired lock on its own time. Such a situation could very easily cause a deadlock, as a program may be waiting on a lock that the garbage collector must release, but while the program is waiting on the lock, no additional garbage is being generated that might trigger a garbage collector run, nor is there any guarantee that even if that run does complete, that the objects you wanted finalized would be.