Skip to content

Commit 4c22055

Browse files
committed
Implemented half sync half async pattern
1 parent 3d488ec commit 4c22055

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed

half-sync-half-async/pom.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0"?>
2+
<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"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>com.iluwatar</groupId>
7+
<artifactId>java-design-patterns</artifactId>
8+
<version>1.5.0</version>
9+
</parent>
10+
<artifactId>half-sync-half-async</artifactId>
11+
<dependencies>
12+
<dependency>
13+
<groupId>junit</groupId>
14+
<artifactId>junit</artifactId>
15+
<scope>test</scope>
16+
</dependency>
17+
<dependency>
18+
<groupId>org.mockito</groupId>
19+
<artifactId>mockito-all</artifactId>
20+
<scope>test</scope>
21+
</dependency>
22+
</dependencies>
23+
<dependencyManagement>
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.mockito</groupId>
27+
<artifactId>mockito-all</artifactId>
28+
<version>1.9.5</version>
29+
</dependency>
30+
</dependencies>
31+
</dependencyManagement>
32+
</project>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.iluwatar.halfsynchalfasync;
2+
3+
import java.util.concurrent.BlockingQueue;
4+
import java.util.concurrent.Callable;
5+
import java.util.concurrent.Future;
6+
import java.util.concurrent.ThreadPoolExecutor;
7+
8+
/**
9+
* This is the asynchronous layer which does not block when a new request arrives. It just passes
10+
* the request to the synchronous layer which consists of a queue i.e. a {@link BlockingQueue} and
11+
* a pool of threads i.e. {@link ThreadPoolExecutor}. Out of this pool of threads one of the thread
12+
* picks up the task and executes it in background and the result is posted back to the caller via
13+
* {@link Future}.
14+
*/
15+
public abstract class AsynchronousService<I, O> {
16+
17+
/*
18+
* This is the synchronous layer to which request to do work is submitted.
19+
*/
20+
private SynchronousLayer syncLayer = new SynchronousLayer();
21+
22+
/**
23+
* Computes arithmetic sum for n
24+
*
25+
* @return future representing arithmetic sum of n
26+
*/
27+
public Future<O> execute(final I input) {
28+
/*
29+
* This is the key part of this pattern where the caller thread does not block until
30+
* the result of work is computed but is delegated to the synchronous layer which
31+
* computes the task in background. This is useful if caller thread is an UI thread,
32+
* which MUST remain responsive to user inputs.
33+
*/
34+
return syncLayer.submit(new Callable<O>() {
35+
36+
@Override
37+
public O call() throws Exception {
38+
return doInBackground(input);
39+
}
40+
41+
});
42+
}
43+
44+
/**
45+
* This method is called in context of background thread where the implementation should compute
46+
* and return the result for input.
47+
*
48+
* @return computed result
49+
*/
50+
protected abstract O doInBackground(I input);
51+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.iluwatar.halfsynchalfasync;
2+
3+
import java.util.concurrent.Callable;
4+
import java.util.concurrent.ExecutorService;
5+
import java.util.concurrent.Future;
6+
import java.util.concurrent.LinkedBlockingQueue;
7+
import java.util.concurrent.ThreadPoolExecutor;
8+
import java.util.concurrent.TimeUnit;
9+
10+
/**
11+
* This represents the Queuing and Synchronous layer of Half-Sync/Half-Async pattern.
12+
* The incoming requests are queued and then picked up by the background threads for execution.
13+
*/
14+
public class SynchronousLayer {
15+
16+
/*
17+
* This is the queuing layer where incoming work is queued
18+
*/
19+
private LinkedBlockingQueue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
20+
/*
21+
* This is the synchronous layer where background threads execute the work
22+
*/
23+
private ExecutorService service = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, tasks);
24+
25+
/**
26+
* Submit new work for backgrounds threads to compute
27+
* @return the result after executing the work
28+
*/
29+
public <T> Future<T> submit(Callable<T> work) {
30+
return service.submit(work);
31+
}
32+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.iluwatar.halfsynchalfasync;
2+
3+
import java.util.concurrent.ExecutionException;
4+
import java.util.concurrent.Future;
5+
6+
import org.junit.Test;
7+
import static org.junit.Assert.*;
8+
9+
public class AsynchronousServiceTest {
10+
11+
@Test
12+
public void test() throws InterruptedException, ExecutionException {
13+
/*
14+
* Addition service is asynchronous layer which does not block on single request,
15+
* and is always available for listening new requests.
16+
*/
17+
ArithmeticSumService service = new ArithmeticSumService();
18+
Future<Long> output1 = service.execute(100L);
19+
Future<Long> output2 = service.execute(50L);
20+
Future<Long> output3 = service.execute(200L);
21+
Future<Long> output4 = service.execute(5L);
22+
23+
assertEquals(ap(100), output1.get().longValue());
24+
assertEquals(ap(50), output2.get().longValue());
25+
assertEquals(ap(200), output3.get().longValue());
26+
assertEquals(ap(5), output4.get().longValue());
27+
}
28+
29+
/*
30+
* This is an asynchronous service which computes arithmetic sum
31+
*/
32+
class ArithmeticSumService extends AsynchronousService<Long, Long> {
33+
34+
@Override
35+
protected Long doInBackground(Long n) {
36+
return (n) * (n + 1) / 2;
37+
}
38+
}
39+
40+
private long ap(int i) {
41+
long out = (i) * (i + 1) / 2;
42+
System.out.println(out);
43+
return out;
44+
}
45+
}

0 commit comments

Comments
 (0)