Skip to content

Commit eeef8bf

Browse files
committed
Refactored code
1 parent dc4904c commit eeef8bf

File tree

6 files changed

+90
-149
lines changed

6 files changed

+90
-149
lines changed

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

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,39 @@
33
import java.util.concurrent.Callable;
44

55
/**
6-
* Represents some computation that is performed asynchronously. The computation is typically
7-
* done is background threads and the result is posted back in form of callback.
6+
* Represents some computation that is performed asynchronously and its result.
7+
* The computation is typically done is background threads and the result is posted
8+
* back in form of callback. The callback does not implement {@code isComplete}, {@code cancel}
9+
* as it is out of scope of this pattern.
810
*
911
* @param <O> type of result
1012
*/
1113
public interface AsyncTask<O> extends Callable<O> {
1214
/**
13-
* Is called in context of caller thread before call to {@link #call()}.
14-
* Validations can be performed here so that the performance penalty of context
15-
* switching is not incurred.
15+
* 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.
1619
*/
1720
void preExecute();
1821

1922
/**
20-
* Is a callback which is called after the result is successfully computed by
21-
* {@link #call()}.
23+
* A callback called after the result is successfully computed by {@link #call()}.
2224
*/
2325
void onResult(O result);
2426

27+
/**
28+
* 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.
30+
*
31+
* @param throwable error cause
32+
*/
2533
void onError(Throwable throwable);
2634

35+
/**
36+
* This is where the computation of task should reside. This method is called in context
37+
* of background thread.
38+
*/
2739
@Override
2840
O call() throws Exception;
2941
}
Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,77 @@
11
package com.iluwatar.halfsynchalfasync;
22

33
import java.util.concurrent.BlockingQueue;
4-
import java.util.concurrent.Future;
4+
import java.util.concurrent.ExecutionException;
5+
import java.util.concurrent.ExecutorService;
6+
import java.util.concurrent.FutureTask;
57
import java.util.concurrent.ThreadPoolExecutor;
8+
import java.util.concurrent.TimeUnit;
69

710
/**
811
* This is the asynchronous layer which does not block when a new request arrives. It just passes
912
* the request to the synchronous layer which consists of a queue i.e. a {@link BlockingQueue} and
10-
* a pool of threads i.e. {@link ThreadPoolExecutor}. Out of this pool of threads one of the thread
11-
* picks up the task and executes it in background and the result is posted back to the caller via
12-
* {@link Future}.
13+
* a pool of threads i.e. {@link ThreadPoolExecutor}. Out of this pool of worker threads one of the
14+
* thread picks up the task and executes it synchronously in background and the result is posted back
15+
* to the caller via callback.
1316
*/
1417
public class AsynchronousService {
1518

1619
/*
17-
* This is the synchronous layer to which request to do work is delegated.
20+
* This represents the queuing layer as well as synchronous layer of the pattern. The thread
21+
* pool contains worker threads which execute the tasks in blocking/synchronous manner. Long
22+
* running tasks should be performed in the background which does not affect the performance of
23+
* main thread.
1824
*/
19-
private SynchronousLayer syncLayer;
20-
21-
public AsynchronousService(QueuingLayer queuingLayer) {
22-
this.syncLayer = new SynchronousLayer(queuingLayer);
25+
private ExecutorService service;
26+
27+
/**
28+
* Creates an asynchronous service using {@code workQueue} as communication channel between
29+
* asynchronous layer and synchronous layer. Different types of queues such as Priority queue,
30+
* can be used to control the pattern of communication between the layers.
31+
*/
32+
public AsynchronousService(BlockingQueue<Runnable> workQueue) {
33+
service = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, workQueue);
2334
}
2435

36+
2537
/**
26-
*
38+
* A non-blocking method which performs the task provided in background and returns immediately.
39+
* <p>
40+
* 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
42+
* due to some exception then the reason for error is posted back using callback method
43+
* {@link AsyncTask#onError(Throwable)}.
44+
* <p>
45+
* 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.
2748
*/
28-
public void execute(final AsyncTask<?> task) {
29-
/*
30-
* This is the key part of this pattern where the caller thread does not block until
31-
* the result of work is computed but is delegated to the synchronous layer which
32-
* computes the task in background. This is useful if caller thread is an UI thread,
33-
* which MUST remain responsive to user inputs.
34-
*/
35-
syncLayer.execute(task);
49+
public <T> void execute(final AsyncTask<T> task) {
50+
try {
51+
// some small tasks such as validation can be performed here.
52+
task.preExecute();
53+
} catch (Exception e) {
54+
task.onError(e);
55+
}
56+
57+
service.submit(new FutureTask<T>(task) {
58+
@Override
59+
protected void done() {
60+
super.done();
61+
try {
62+
/* called in context of background thread. There is other variant possible
63+
* where result is posted back and sits in the queue of caller thread which
64+
* then picks it up for processing. An example of such a system is Android OS,
65+
* where the UI elements can only be updated using UI thread. So result must be
66+
* posted back in UI thread.
67+
*/
68+
task.onResult(get());
69+
} catch (InterruptedException e) {
70+
// should not occur
71+
} catch (ExecutionException e) {
72+
task.onError(e.getCause());
73+
}
74+
}
75+
});
3676
}
3777
}

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

Lines changed: 0 additions & 8 deletions
This file was deleted.

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

Lines changed: 0 additions & 54 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.iluwatar.halfsynchalfasync;
2+
3+
import java.util.concurrent.ExecutionException;
4+
5+
import org.junit.Test;
6+
7+
public class AppTest {
8+
9+
@Test
10+
public void test() throws InterruptedException, ExecutionException {
11+
App.main(null);
12+
}
13+
}

half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AsynchronousServiceTest.java

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)