package ch.claude_martin.enums.proxy; import static java.util.Objects.requireNonNull; import java.lang.reflect.Proxy; import java.util.Collections; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Allows to make any object thread-safe. This works similar to * {@link Collections#synchronizedCollection(java.util.Collection)}. But this * uses a proxy, which will synchronize on the object. * *

* The object must implement some interface so that the returned proxy can be * used as an implementation of that interface. * *

* Note: This does not make the elements within the object thread-safe. This * only works if the object hides all information and no other objects share * references to the inner data structures. * * @author Claude Martin */ public class SynchronizedObject { /** * Returns a proxy instance which will synchronize all calls to the object. * * @param object * The object which will be used for synchronization and to redirect * all method invocations. * @param type * The interface type of the returned proxy. Both the object and the * proxy will share this interface. * @return A new tread-safe proxy. */ @SuppressWarnings("unchecked") public static I synchronize(final T object, final Class type) { return (I) Proxy.newProxyInstance(// requireNonNull(object).getClass().getClassLoader(),// new Class[] { requireNonNull(type) },// (proxy, method, args) -> { synchronized (object) { return method.invoke(object, args); } }); } /** * Returns a proxy instance which will synchronize all calls to the object * using a given lock. * * @param object * The object which will be used for synchronization and to redirect * all method invocations. * @param type * The interface type of the returned proxy. Both the object and the * proxy will share this interface. * @param lock * A lock object used to obtain a lock. * @return A new tread-safe proxy. */ @SuppressWarnings("unchecked") public static I synchronize(final T object, final Class type, final Lock lock) { return (I) Proxy.newProxyInstance(// requireNonNull(object).getClass().getClassLoader(),// new Class[] { requireNonNull(type) },// (proxy, method, args) -> { lock.lock(); try { return method.invoke(object, args); } finally { lock.unlock(); } }); } } ----------------------------- ----------------------------- (The rest is just for testing) public final class SynchronizedObjectTest { public static void main(final String[] args) throws InterruptedException { final ICounter counter = synchronize(new Counter(), ICounter.class); final ExecutorService pool = Executors.newCachedThreadPool(); for (int i = 0; i < 10000; i++) pool.execute(() -> counter.increment()); pool.shutdown(); pool.awaitTermination(1, TimeUnit.MINUTES); System.out.println(counter.get()); } static interface ICounter { public int get(); public void increment(); } static class Counter implements ICounter { int i = 0; @Override public int get() { return this.i; } @Override public void increment() { this.i++; } } }