Using the work queue idiom and JDK4 proxies, one can automate serializing calls into an interface:
public class FacadeFactory<T> {
private final Class<T> interfaz;
private final BlockingQueue<Frame> queue;
private final ExecutorService pool;
public FacadeFactory(final Class<T> interfaz,
final BlockingQueue<Frame> queue, final ExecutorService pool) {
this.interfaz = interfaz;
this.queue = queue;
this.pool = pool;
}
public T facade(final T delegate) {
pool.submit(new Callable<Void>() {
public Void call() {
final List<Frame> work = new ArrayList<Frame>();
for (; ;) {
try {
work.add(queue.take());
} catch (final InterruptedException e) {
currentThread().interrupt();
return null;
}
queue.drainTo(work);
for (final Frame frame : work)
frame.apply(delegate);
work.clear();
}
}
});
return interfaz.cast(newProxyInstance(interfaz.getClassLoader(),
new Class<?>[]{interfaz}, new InvocationHandler() {
public Object invoke(final Object proxy,
final Method method, final Object[] args)
throws Throwable {
queue.offer(new Frame(method, args));
return null;
}
}));
}
public class Frame {
final Method method;
final Object[] args;
private Frame(final Method method, final Object[] args) {
this.method = method;
this.args = args;
}
private void apply(final T delegate) {
try {
method.invoke(delegate, args);
} catch (final IllegalAccessException e) {
throw new Error(e);
} catch (final InvocationTargetException e) {
throw new Error(e);
}
}
}
} In other words, turn calls against an interface spread across several threads into a sequence of single-threaded calls on a worker thread.
My motivation is isolating legacy non-thread-safe code in a threaded program without refactoring either the callers or the legacy code. I use a wrapper instead to make the many-threads to one-thread fix.
Sample use:
public class FacadeFactoryTest {
private FacadeFactory<Bob> factory;
@Before
public void setUp() {
factory = new FacadeFactory<Bob>(Bob.class,
new ArrayBlockingQueue<FacadeFactory<Bob>.Frame>(1),
newSingleThreadExecutor());
}
@Test(timeout = 100L)
public void testFoo()
throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
factory.facade(new Bob() {
public void dooby() {
latch.countDown();
}
}).dooby();
latch.await();
}
public static interface Bob {
void dooby();
}
}
No comments:
Post a Comment