Skip to content

Commit f778b2c

Browse files
committed
Changed method names and did proper documentation
1 parent eeef8bf commit f778b2c

File tree

5 files changed

+208
-12
lines changed

5 files changed

+208
-12
lines changed
32.1 KB
Loading
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
3+
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
4+
<class id="1" language="java" name="com.iluwatar.halfsynchalfasync.AsynchronousService" project="half-sync-half-async"
5+
file="/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java" binary="false"
6+
corner="BOTTOM_RIGHT">
7+
<position height="115" width="265" x="41" y="37"/>
8+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
9+
sort-features="false" accessors="true" visibility="true">
10+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
11+
<operations public="true" package="true" protected="true" private="true" static="true"/>
12+
</display>
13+
</class>
14+
<interface id="2" language="java" name="com.iluwatar.halfsynchalfasync.AsyncTask" project="half-sync-half-async"
15+
file="/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsyncTask.java" binary="false"
16+
corner="BOTTOM_RIGHT">
17+
<position height="-1" width="-1" x="776" y="223"/>
18+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
19+
sort-features="false" accessors="true" visibility="true">
20+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
21+
<operations public="true" package="true" protected="true" private="true" static="true"/>
22+
</display>
23+
</interface>
24+
<interface id="3" language="java" name="java.util.concurrent.BlockingQueue" project="async-method-invocation"
25+
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
26+
<position height="-1" width="-1" x="494" y="310"/>
27+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
28+
sort-features="false" accessors="true" visibility="true">
29+
<attributes public="false" package="false" protected="false" private="false" static="true"/>
30+
<operations public="false" package="false" protected="false" private="false" static="true"/>
31+
</display>
32+
</interface>
33+
<class id="4" language="java" name="java.util.concurrent.ThreadPoolExecutor" project="async-method-invocation"
34+
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
35+
<position height="-1" width="-1" x="174" y="343"/>
36+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
37+
sort-features="false" accessors="true" visibility="true">
38+
<attributes public="true" package="true" protected="true" private="false" static="true"/>
39+
<operations public="false" package="false" protected="false" private="false" static="false"/>
40+
</display>
41+
</class>
42+
<interface id="5" language="java" name="java.util.concurrent.Callable" project="async-method-invocation"
43+
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
44+
<position height="-1" width="-1" x="772" y="47"/>
45+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
46+
sort-features="false" accessors="true" visibility="true">
47+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
48+
<operations public="true" package="true" protected="true" private="true" static="true"/>
49+
</display>
50+
</interface>
51+
<generalization id="6">
52+
<end type="SOURCE" refId="2"/>
53+
<end type="TARGET" refId="5"/>
54+
</generalization>
55+
<association id="7">
56+
<end type="SOURCE" refId="4" navigable="false">
57+
<attribute id="8" name="workQueue"/>
58+
<multiplicity id="9" minimum="0" maximum="1"/>
59+
</end>
60+
<end type="TARGET" refId="3" navigable="true"/>
61+
<display labels="true" multiplicity="true"/>
62+
</association>
63+
<dependency id="10">
64+
<end type="SOURCE" refId="1"/>
65+
<end type="TARGET" refId="3"/>
66+
</dependency>
67+
<dependency id="11">
68+
<end type="SOURCE" refId="1"/>
69+
<end type="TARGET" refId="4"/>
70+
</dependency>
71+
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
72+
sort-features="false" accessors="true" visibility="true">
73+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
74+
<operations public="true" package="true" protected="true" private="true" static="true"/>
75+
</classifier-display>
76+
<association-display labels="true" multiplicity="true"/>
77+
</class-diagram>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.iluwatar.halfsynchalfasync;
2+
3+
import java.util.concurrent.LinkedBlockingQueue;
4+
5+
/**
6+
* This application demonstrates Half-Sync/Half-Async pattern. Key parts of the pattern are
7+
* {@link AsyncTask} and {@link AsynchronousService}.
8+
*
9+
* <p>
10+
* <i>PROBLEM</i>
11+
* <br/>
12+
* A concurrent system have a mixture of short duration, mid duration and long duration tasks.
13+
* Mid or long duration tasks should be performed asynchronously to meet quality of service
14+
* requirements.
15+
*
16+
* <p><i>INTENT</i>
17+
* <br/>
18+
* The intent of this pattern is to separate the the synchronous and asynchronous processing
19+
* in the concurrent application by introducing two intercommunicating layers - one for sync
20+
* and one for async. This simplifies the programming without unduly affecting the performance.
21+
*
22+
* <p>
23+
* <i>APPLICABILITY</i>
24+
* <br/>
25+
* <ul>
26+
* <li>UNIX network subsystems - In operating systems network operations are carried out
27+
* asynchronously with help of hardware level interrupts.</li>
28+
* <li>CORBA - At the asynchronous layer one thread is associated with each socket that is
29+
* connected to the client. Thread blocks waiting for CORBA requests from the client. On receiving
30+
* request it is inserted in the queuing layer which is then picked up by synchronous layer which
31+
* processes the request and sends response back to the client.</li>
32+
* <li>Android AsyncTask framework - Framework provides a way to execute long running blocking calls,
33+
* such as downloading a file, in background threads so that the UI thread remains free to respond
34+
* to user inputs.</i>
35+
* </ul>
36+
*
37+
* <p>
38+
* <i>IMPLEMENTATION</i>
39+
* <br/>
40+
* The main method creates an asynchronous service which does not block the main thread while
41+
* the task is being performed. The main thread continues its work which is similar to Async Method
42+
* Invocation pattern. The difference between them is that there is a queuing layer between Asynchronous
43+
* layer and synchronous layer, which allows for different communication patterns between both layers.
44+
* Such as Priority Queue can be used as queuing layer to prioritize the way tasks are executed.
45+
* Our implementation is just one simple way of implementing this pattern, there are many variants possible
46+
* as described in its applications.
47+
*/
48+
public class App {
49+
50+
public static void main(String[] args) {
51+
AsynchronousService service = new AsynchronousService(new LinkedBlockingQueue<>());
52+
/*
53+
* A new task to calculate sum is received but as this is main thread, it should not block.
54+
* So it passes it to the asynchronous task layer to compute and proceeds with handling other
55+
* incoming requests. This is particularly useful when main thread is waiting on Socket to receive
56+
* new incoming requests and does not wait for particular request to be completed before responding
57+
* to new request.
58+
*/
59+
service.execute(new ArithmeticSumTask(1000));
60+
61+
/* New task received, lets pass that to async layer for computation. So both requests will be
62+
* executed in parallel.
63+
*/
64+
service.execute(new ArithmeticSumTask(500));
65+
service.execute(new ArithmeticSumTask(2000));
66+
service.execute(new ArithmeticSumTask(1));
67+
}
68+
69+
static class ArithmeticSumTask implements AsyncTask<Long> {
70+
private long n;
71+
72+
public ArithmeticSumTask(long n) {
73+
this.n = n;
74+
}
75+
76+
/*
77+
* This is the long running task that is performed in background. In our example
78+
* the long running task is calculating arithmetic sum with artificial delay.
79+
*/
80+
@Override
81+
public Long call() throws Exception {
82+
return ap(n);
83+
}
84+
85+
/*
86+
* This will be called in context of the main thread where some validations can be
87+
* done regarding the inputs. Such as it must be greater than 0. It's a small
88+
* computation which can be performed in main thread. If we did validated the input
89+
* in background thread then we pay the cost of context switching
90+
* which is much more than validating it in main thread.
91+
*/
92+
@Override
93+
public void onPreCall() {
94+
if (n < 0) {
95+
throw new IllegalArgumentException("n is less than 0");
96+
}
97+
}
98+
99+
@Override
100+
public void onPostCall(Long result) {
101+
// Handle the result of computation
102+
System.out.println(result);
103+
}
104+
105+
@Override
106+
public void onError(Throwable throwable) {
107+
throw new IllegalStateException("Should not occur");
108+
}
109+
}
110+
111+
private static long ap(long i) {
112+
try {
113+
Thread.sleep(i);
114+
} catch (InterruptedException e) {
115+
}
116+
return (i) * (i + 1) / 2;
117+
}
118+
}

half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsyncTask.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,23 @@
1313
public interface AsyncTask<O> extends Callable<O> {
1414
/**
1515
* Is called in context of caller thread before call to {@link #call()}. Large
16-
* tasks should not be performed in this method. Validations can be performed here
17-
* so that the performance penalty of context switching is not incurred in case of
18-
* invalid requests.
16+
* tasks should not be performed in this method as it will block the caller thread.
17+
* Small tasks such as validations can be performed here so that the performance penalty
18+
* of context switching is not incurred in case of invalid requests.
1919
*/
20-
void preExecute();
20+
void onPreCall();
2121

2222
/**
23-
* A callback called after the result is successfully computed by {@link #call()}.
23+
* A callback called after the result is successfully computed by {@link #call()}. In our
24+
* implementation this method is called in context of background thread but in some variants,
25+
* such as Android where only UI thread can change the state of UI widgets, this method is called
26+
* in context of UI thread.
2427
*/
25-
void onResult(O result);
28+
void onPostCall(O result);
2629

2730
/**
2831
* A callback called if computing the task resulted in some exception. This method
29-
* is called when either of {@link #call()} or {@link #preExecute()} throw any exception.
32+
* is called when either of {@link #call()} or {@link #onPreCall()} throw any exception.
3033
*
3134
* @param throwable error cause
3235
*/

half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,16 @@ public AsynchronousService(BlockingQueue<Runnable> workQueue) {
3838
* A non-blocking method which performs the task provided in background and returns immediately.
3939
* <p>
4040
* On successful completion of task the result is posted back using callback method
41-
* {@link AsyncTask#onResult(Object)}, if task execution is unable to complete normally
41+
* {@link AsyncTask#onPostCall(Object)}, if task execution is unable to complete normally
4242
* due to some exception then the reason for error is posted back using callback method
4343
* {@link AsyncTask#onError(Throwable)}.
4444
* <p>
4545
* NOTE: The results are posted back in the context of background thread in this implementation.
46-
* There is other variant possible where the result is posted back in the queue of caller thread
47-
* and then the result is processed in context of caller thread.
4846
*/
4947
public <T> void execute(final AsyncTask<T> task) {
5048
try {
5149
// some small tasks such as validation can be performed here.
52-
task.preExecute();
50+
task.onPreCall();
5351
} catch (Exception e) {
5452
task.onError(e);
5553
}
@@ -65,7 +63,7 @@ protected void done() {
6563
* where the UI elements can only be updated using UI thread. So result must be
6664
* posted back in UI thread.
6765
*/
68-
task.onResult(get());
66+
task.onPostCall(get());
6967
} catch (InterruptedException e) {
7068
// should not occur
7169
} catch (ExecutionException e) {

0 commit comments

Comments
 (0)