DulcetAirman icon

SynchronizedObject

DulcetAirman | PRO | 01/02/14 02:51:40 PM UTC | 0 ⭐ | 535 👁️ | Never ⏰ | []
Java |

3.54 KB

|

None

|

0 👍

/

0 👎

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.
 * 
 * <p>
 * The object must implement some interface so that the returned proxy can be
 * used as an implementation of that interface.
 * 
 * <p>
 * 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, T extends I> I synchronize(final T object, final Class<I> 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, T extends I> I synchronize(final T object, final Class<I> 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++;
        }
    }
}

Comments