I'm going to vote for the second option. Classes in general should not be thread-safe (and so not be internally synchronized). The safety costs time and is often not needed. Further, you often get situations like: if (list.isEmpty()) list.add( filler );
. If both methods are synchronized internally it does no good. The list can be empty on the first call and have 1,000,000 entries when the add
call is made. The whole statement must be synchronized to be useful.
More generally, you need to decide, for each class, whether it is thread-safe or not. The ones that aren't will be faster and can be made thread-safe by the caller who, as in the above instance, may need some flexibility in how they go about it. Also, there are clever ways to avoid any need for synchronization at all, such as referencing a class from a single thread. Most Java Collections Framework classes are not and should not be thread-safe. Thread-safety should generally be handled at a high level rather than a low level.
Every once in a while you get a low level class that has to handle a lot of thread traffic, and then you do need a class that is thread-safe. My favorite example is JavaConcurrentSkipListMap, which does the same job as TreeMap. I use TreeMap 100 times for every time I use JCSLM, but when I do need it it's a lifesaver. (Without it, I'd have stuck with Java 1.4.)
If you are going to make a class thread-safe, do something besides synchronizing methods. You can end up blocking other threads when you don't need to. Someone else may synchronize on your class and so block methods that don't need to be blocked. At the very least synchronize on an internal object that exists purely for synchronization. Better still, synch on logical groups of fields within your class, and only place synch blocks where you need them.
There are other ways to be thread-safe without synchronization--immutable objects, compare-and-swap, etc. Also, firing up other threads so the main thread is not blocked can avoid critical bottlenecks, even if it adds to your machine's overall workload.
That said, I have had good luck, on rare occasion, just synchronizing every method in a class. And I can (intentionally) lock the whole thing just by synching on the class. It's simple and safe, and does no harm if the class is lightly used. But I sometimes guess wrong about class usage and have to give up on it when my program hangs, using only 2% of CPU despite 4 hyperthreaded cores.
I should perhaps add that most of my work has been with time critical software. But too much synchronization, even without actual deadlocks, can make any program run way too slow for any purpose. And if time doesn't matter, you should not be using multiple threads.