Implemented half sync half async pattern
This commit is contained in:
parent
3d488ec15a
commit
4c22055e47
32
half-sync-half-async/pom.xml
Normal file
32
half-sync-half-async/pom.xml
Normal 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>
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user