// code exactly taken from java concurrency in practice
public class TimingThreadPool extends ThreadPoolExecutor {
private final ThreadLocal<Long> startTime
= new ThreadLocal<Long>();
private final Logger log = Logger.getLogger("TimingThreadPool");
private final AtomicLong numTasks = new AtomicLong();
private final AtomicLong totalTime = new AtomicLong();
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
log.fine(String.format("Thread %s: start %s", t, r));
startTime.set(System.nanoTime());
}
protected void afterExecute(Runnable r, Throwable t) {
try {
long endTime = System.nanoTime();
long taskTime = endTime - startTime.get();
numTasks.incrementAndGet();
totalTime.addAndGet(taskTime);
log.fine(String.format("Thread %s: end %s, time=%dns",
t, r, taskTime));
} finally {
super.afterExecute(r, t);
}
}
protected void terminated() {
try {
log.info(String.format("Terminated: avg time=%dns",
totalTime.get() / numTasks.get()));
} finally {
super.terminated();
}
}
}
Is the ThreadPoolExecutor instance is shared by all the worker threads. If yes then the method beforeExecute(...) and afterExecute(...) shouldn’t be synchronized? If the answer is NO then is the reason is ” the local variables are assigned in thread stack and the state variables like numTasks, totalTime, startTime are thread confined / atomic”.
You do not need to synchronized beforeExecute and afterExecute because all fields used in these two methods are thread-safe java.util.logging.Logger (from API – all methods on Logger are multi-thread safe.) or ThreadLocal and AtocmicLong specially designed for lock-free usage.
As for local variables they are accessible to only one thread and do not need any synchronization.