Changed method names and did proper documentation

This commit is contained in:
Narendra Pathai 2015-07-29 16:12:27 +05:30
parent eeef8bf475
commit f778b2cc04
5 changed files with 208 additions and 12 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.halfsynchalfasync.AsynchronousService" project="half-sync-half-async"
file="/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="115" width="265" x="41" y="37"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="2" language="java" name="com.iluwatar.halfsynchalfasync.AsyncTask" project="half-sync-half-async"
file="/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsyncTask.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="776" y="223"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<interface id="3" language="java" name="java.util.concurrent.BlockingQueue" project="async-method-invocation"
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="494" y="310"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="false" package="false" protected="false" private="false" static="true"/>
<operations public="false" package="false" protected="false" private="false" static="true"/>
</display>
</interface>
<class id="4" language="java" name="java.util.concurrent.ThreadPoolExecutor" project="async-method-invocation"
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="174" y="343"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="false" static="true"/>
<operations public="false" package="false" protected="false" private="false" static="false"/>
</display>
</class>
<interface id="5" language="java" name="java.util.concurrent.Callable" project="async-method-invocation"
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="772" y="47"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<generalization id="6">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="5"/>
</generalization>
<association id="7">
<end type="SOURCE" refId="4" navigable="false">
<attribute id="8" name="workQueue"/>
<multiplicity id="9" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="3" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<dependency id="10">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</dependency>
<dependency id="11">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="4"/>
</dependency>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

View File

@ -0,0 +1,118 @@
package com.iluwatar.halfsynchalfasync;
import java.util.concurrent.LinkedBlockingQueue;
/**
* This application demonstrates Half-Sync/Half-Async pattern. Key parts of the pattern are
* {@link AsyncTask} and {@link AsynchronousService}.
*
* <p>
* <i>PROBLEM</i>
* <br/>
* A concurrent system have a mixture of short duration, mid duration and long duration tasks.
* Mid or long duration tasks should be performed asynchronously to meet quality of service
* requirements.
*
* <p><i>INTENT</i>
* <br/>
* The intent of this pattern is to separate the the synchronous and asynchronous processing
* in the concurrent application by introducing two intercommunicating layers - one for sync
* and one for async. This simplifies the programming without unduly affecting the performance.
*
* <p>
* <i>APPLICABILITY</i>
* <br/>
* <ul>
* <li>UNIX network subsystems - In operating systems network operations are carried out
* asynchronously with help of hardware level interrupts.</li>
* <li>CORBA - At the asynchronous layer one thread is associated with each socket that is
* connected to the client. Thread blocks waiting for CORBA requests from the client. On receiving
* request it is inserted in the queuing layer which is then picked up by synchronous layer which
* processes the request and sends response back to the client.</li>
* <li>Android AsyncTask framework - Framework provides a way to execute long running blocking calls,
* such as downloading a file, in background threads so that the UI thread remains free to respond
* to user inputs.</i>
* </ul>
*
* <p>
* <i>IMPLEMENTATION</i>
* <br/>
* The main method creates an asynchronous service which does not block the main thread while
* the task is being performed. The main thread continues its work which is similar to Async Method
* Invocation pattern. The difference between them is that there is a queuing layer between Asynchronous
* layer and synchronous layer, which allows for different communication patterns between both layers.
* Such as Priority Queue can be used as queuing layer to prioritize the way tasks are executed.
* Our implementation is just one simple way of implementing this pattern, there are many variants possible
* as described in its applications.
*/
public class App {
public static void main(String[] args) {
AsynchronousService service = new AsynchronousService(new LinkedBlockingQueue<>());
/*
* A new task to calculate sum is received but as this is main thread, it should not block.
* So it passes it to the asynchronous task layer to compute and proceeds with handling other
* incoming requests. This is particularly useful when main thread is waiting on Socket to receive
* new incoming requests and does not wait for particular request to be completed before responding
* to new request.
*/
service.execute(new ArithmeticSumTask(1000));
/* New task received, lets pass that to async layer for computation. So both requests will be
* executed in parallel.
*/
service.execute(new ArithmeticSumTask(500));
service.execute(new ArithmeticSumTask(2000));
service.execute(new ArithmeticSumTask(1));
}
static class ArithmeticSumTask implements AsyncTask<Long> {
private long n;
public ArithmeticSumTask(long n) {
this.n = n;
}
/*
* This is the long running task that is performed in background. In our example
* the long running task is calculating arithmetic sum with artificial delay.
*/
@Override
public Long call() throws Exception {
return ap(n);
}
/*
* This will be called in context of the main thread where some validations can be
* done regarding the inputs. Such as it must be greater than 0. It's a small
* computation which can be performed in main thread. If we did validated the input
* in background thread then we pay the cost of context switching
* which is much more than validating it in main thread.
*/
@Override
public void onPreCall() {
if (n < 0) {
throw new IllegalArgumentException("n is less than 0");
}
}
@Override
public void onPostCall(Long result) {
// Handle the result of computation
System.out.println(result);
}
@Override
public void onError(Throwable throwable) {
throw new IllegalStateException("Should not occur");
}
}
private static long ap(long i) {
try {
Thread.sleep(i);
} catch (InterruptedException e) {
}
return (i) * (i + 1) / 2;
}
}

View File

@ -13,20 +13,23 @@ import java.util.concurrent.Callable;
public interface AsyncTask<O> extends Callable<O> { public interface AsyncTask<O> extends Callable<O> {
/** /**
* Is called in context of caller thread before call to {@link #call()}. Large * Is called in context of caller thread before call to {@link #call()}. Large
* tasks should not be performed in this method. Validations can be performed here * tasks should not be performed in this method as it will block the caller thread.
* so that the performance penalty of context switching is not incurred in case of * Small tasks such as validations can be performed here so that the performance penalty
* invalid requests. * of context switching is not incurred in case of invalid requests.
*/ */
void preExecute(); void onPreCall();
/** /**
* A callback called after the result is successfully computed by {@link #call()}. * A callback called after the result is successfully computed by {@link #call()}. In our
* implementation this method is called in context of background thread but in some variants,
* such as Android where only UI thread can change the state of UI widgets, this method is called
* in context of UI thread.
*/ */
void onResult(O result); void onPostCall(O result);
/** /**
* A callback called if computing the task resulted in some exception. This method * A callback called if computing the task resulted in some exception. This method
* is called when either of {@link #call()} or {@link #preExecute()} throw any exception. * is called when either of {@link #call()} or {@link #onPreCall()} throw any exception.
* *
* @param throwable error cause * @param throwable error cause
*/ */

View File

@ -38,18 +38,16 @@ public class AsynchronousService {
* A non-blocking method which performs the task provided in background and returns immediately. * A non-blocking method which performs the task provided in background and returns immediately.
* <p> * <p>
* On successful completion of task the result is posted back using callback method * On successful completion of task the result is posted back using callback method
* {@link AsyncTask#onResult(Object)}, if task execution is unable to complete normally * {@link AsyncTask#onPostCall(Object)}, if task execution is unable to complete normally
* due to some exception then the reason for error is posted back using callback method * due to some exception then the reason for error is posted back using callback method
* {@link AsyncTask#onError(Throwable)}. * {@link AsyncTask#onError(Throwable)}.
* <p> * <p>
* NOTE: The results are posted back in the context of background thread in this implementation. * NOTE: The results are posted back in the context of background thread in this implementation.
* There is other variant possible where the result is posted back in the queue of caller thread
* and then the result is processed in context of caller thread.
*/ */
public <T> void execute(final AsyncTask<T> task) { public <T> void execute(final AsyncTask<T> task) {
try { try {
// some small tasks such as validation can be performed here. // some small tasks such as validation can be performed here.
task.preExecute(); task.onPreCall();
} catch (Exception e) { } catch (Exception e) {
task.onError(e); task.onError(e);
} }
@ -65,7 +63,7 @@ public class AsynchronousService {
* where the UI elements can only be updated using UI thread. So result must be * where the UI elements can only be updated using UI thread. So result must be
* posted back in UI thread. * posted back in UI thread.
*/ */
task.onResult(get()); task.onPostCall(get());
} catch (InterruptedException e) { } catch (InterruptedException e) {
// should not occur // should not occur
} catch (ExecutionException e) { } catch (ExecutionException e) {