Implemented half sync half async pattern

This commit is contained in:
Narendra Pathai 2015-07-25 15:58:12 +05:30
parent 3d488ec15a
commit 4c22055e47
4 changed files with 160 additions and 0 deletions

View File

@ -0,0 +1,32 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.5.0</version>
</parent>
<artifactId>half-sync-half-async</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -0,0 +1,51 @@
package com.iluwatar.halfsynchalfasync;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* This is the asynchronous layer which does not block when a new request arrives. It just passes
* the request to the synchronous layer which consists of a queue i.e. a {@link BlockingQueue} and
* a pool of threads i.e. {@link ThreadPoolExecutor}. Out of this pool of threads one of the thread
* picks up the task and executes it in background and the result is posted back to the caller via
* {@link Future}.
*/
public abstract class AsynchronousService<I, O> {
/*
* This is the synchronous layer to which request to do work is submitted.
*/
private SynchronousLayer syncLayer = new SynchronousLayer();
/**
* Computes arithmetic sum for n
*
* @return future representing arithmetic sum of n
*/
public Future<O> execute(final I input) {
/*
* This is the key part of this pattern where the caller thread does not block until
* the result of work is computed but is delegated to the synchronous layer which
* computes the task in background. This is useful if caller thread is an UI thread,
* which MUST remain responsive to user inputs.
*/
return syncLayer.submit(new Callable<O>() {
@Override
public O call() throws Exception {
return doInBackground(input);
}
});
}
/**
* This method is called in context of background thread where the implementation should compute
* and return the result for input.
*
* @return computed result
*/
protected abstract O doInBackground(I input);
}

View File

@ -0,0 +1,32 @@
package com.iluwatar.halfsynchalfasync;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* This represents the Queuing and Synchronous layer of Half-Sync/Half-Async pattern.
* The incoming requests are queued and then picked up by the background threads for execution.
*/
public class SynchronousLayer {
/*
* This is the queuing layer where incoming work is queued
*/
private LinkedBlockingQueue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
/*
* This is the synchronous layer where background threads execute the work
*/
private ExecutorService service = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, tasks);
/**
* Submit new work for backgrounds threads to compute
* @return the result after executing the work
*/
public <T> Future<T> submit(Callable<T> work) {
return service.submit(work);
}
}

View File

@ -0,0 +1,45 @@
package com.iluwatar.halfsynchalfasync;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.junit.Test;
import static org.junit.Assert.*;
public class AsynchronousServiceTest {
@Test
public void test() throws InterruptedException, ExecutionException {
/*
* Addition service is asynchronous layer which does not block on single request,
* and is always available for listening new requests.
*/
ArithmeticSumService service = new ArithmeticSumService();
Future<Long> output1 = service.execute(100L);
Future<Long> output2 = service.execute(50L);
Future<Long> output3 = service.execute(200L);
Future<Long> output4 = service.execute(5L);
assertEquals(ap(100), output1.get().longValue());
assertEquals(ap(50), output2.get().longValue());
assertEquals(ap(200), output3.get().longValue());
assertEquals(ap(5), output4.get().longValue());
}
/*
* This is an asynchronous service which computes arithmetic sum
*/
class ArithmeticSumService extends AsynchronousService<Long, Long> {
@Override
protected Long doInBackground(Long n) {
return (n) * (n + 1) / 2;
}
}
private long ap(int i) {
long out = (i) * (i + 1) / 2;
System.out.println(out);
return out;
}
}