A ReentrantLock is a different tool for a different use-case. While you can use both for most synchronization issues (that's what they are made for), the come with different advantages and disadvantages.
Synchronized is at most simple: you write synchronized and that's it. With modern JVMs it is reasonable fast, but has the drawback that it puts all threads that try to enter a synchronized block on hold, whether they actually need to or not. If you use synchronized too often, this can dramatically reduce the speed of multi-threading, worst case down to a point where single-threaded execution would have been faster.
As threading issues only occur if someone is writing while someone else is reading/writing the same data section, programs often run into the problem, that they could theoretically run without synchronization, because most threads just read, but there is this one occasional write, which enforces the synchronized block. This is what the Locks were made for: you have a finer control over when you actually synchronize.
The basic ReentrantLock allows - beside a fair parameter in the constructor - that you can decide when you release the lock, and you can do it at multiple points, so when it suits you best. Other variations of it like the ReentrantReadWriteLock allow you to have many unsynchronized reads, except if there is a write. The downside is that this is solved in Java code, which makes it noticeably slower than the "native" synchronized block. That said: you should only use it, if you know that the optimization gain using this lock is bigger than the loss.
Under normal situations you can only tell the difference in speed if you actually monitor it, by running a profiler to check the speed before and afterwards in a sophisticated way.