|
1 | 1 | package com.iluwatar.halfsynchalfasync; |
2 | 2 |
|
3 | 3 | 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; |
5 | 7 | import java.util.concurrent.ThreadPoolExecutor; |
| 8 | +import java.util.concurrent.TimeUnit; |
6 | 9 |
|
7 | 10 | /** |
8 | 11 | * This is the asynchronous layer which does not block when a new request arrives. It just passes |
9 | 12 | * 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. |
13 | 16 | */ |
14 | 17 | public class AsynchronousService { |
15 | 18 |
|
16 | 19 | /* |
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. |
18 | 24 | */ |
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); |
23 | 34 | } |
24 | 35 |
|
| 36 | + |
25 | 37 | /** |
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. |
27 | 48 | */ |
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 | + }); |
36 | 76 | } |
37 | 77 | } |
0 commit comments