// lowlevel/SynchronizedComparison.java // (c)2017 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Synchronizing blocks instead of entire methods // speeds up access. import java.util.*; import java.util.stream.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import onjava.Nap; abstract class Guarded { AtomicLong callCount = new AtomicLong(); public abstract void method(); @Override public String toString() { return getClass().getSimpleName() + ": " + callCount.get(); } } class SynchronizedMethod extends Guarded { public synchronized void method() { new Nap(0.01); callCount.incrementAndGet(); } } class CriticalSection extends Guarded { public void method() { new Nap(0.01); synchronized(this) { callCount.incrementAndGet(); } } } class Caller implements Runnable { private Guarded g; public Caller(Guarded g) { this.g = g; } private AtomicLong successfulCalls = new AtomicLong(); private AtomicBoolean stop = new AtomicBoolean(false); @Override public void run() { new Timer().schedule(new TimerTask() { public void run() { stop.set(true); } }, 2500); while(!stop.get()) { g.method(); successfulCalls.getAndIncrement(); } System.out.println( "-> " + successfulCalls.get()); } } public class SynchronizedComparison { static void test(Guarded g) { List> callers = Stream.of( new Caller(g), new Caller(g), new Caller(g), new Caller(g)) .map(CompletableFuture::runAsync) .collect(Collectors.toList()); callers.forEach(CompletableFuture::join); System.out.println(g); } public static void main(String[] args) { test(new CriticalSection()); test(new SynchronizedMethod()); } } /* Output: -> 152 -> 152 -> 153 -> 153 CriticalSection: 610 -> 44 -> 28 -> 62 -> 24 SynchronizedMethod: 158 */