The only difference is reducing a number of operations guarded by a lock which can improve performance much.
Example: let's imagine we have a servlet which gives an array of factors of a big number on input, and we want to count how often the servlet is launched. The problem is synchronizing the access to the state variable requestsCount
//Poor performance
class PoorFactorizer implements Servlet {
private int requestsCount = 0;
public synchronized void service(ServletRequest req, ServletResponse res) {
BigInteger numberToFactorize = extractFromRequest(req);
BigInteger[] factors = factorize(numberToFactorize); // long lasting
// operation makes everyone wait
requestCount++;
encodeResponse(res, factors);
}
}
//Better perfomance
class PoorFactorizer implements Servlet {
private int requestsCount = 0;
public void service(ServletRequest req, ServletResponse res) {
BigInteger numberToFactorize = extractFromRequest(req);
BigInteger[] factors = factorize(numberToFactorize);
// since we need to guard only the class' state
// let's guard only the operation with the state
synchronized(this) {
requestCount++;
}
encodeResponse(res, factors);
}
}
UPD: you can read a very good explanation in a masterpiece "Java Concurrency in Practice" (chapter 2). I highly recommend to read this book from cover to cover.