ForkJoinContext.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-1.6.0).
003  * Copyright (c) 2007-2014 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.util;
021 
022 import static java.util.Objects.requireNonNull;
023 
024 import java.util.concurrent.CancellationException;
025 import java.util.concurrent.ExecutionException;
026 import java.util.concurrent.ForkJoinPool;
027 import java.util.concurrent.Future;
028 import java.util.concurrent.atomic.AtomicReference;
029 
030 import javolution.context.ConcurrentContext;
031 import javolution.context.ObjectFactory;
032 import javolution.util.FastList;
033 
034 /**
035  * Since the parallelization of the library is build on the {@link ConcurrentContext}
036  * of the <a href="http://javolution.org/">Javolution</a> project, this class
037  * allows you to share a common {@link ForkJoinPool} for the GA and the rest of
038  * your application.
039  <p/>
040  * The following example shows how to use the {@code ForkJoinContext} directly:
041  * [code]
042  * public class Main {
043  *     public static void main(final String[] args) {
044  *         final int nthreads = 10;
045  *
046  *         // Create a java ForkJoinPool and initialize the ForkJoinContext.
047  *         final ForkJoinPool pool = new ForkJoinPool(nthreads);
048  *         ForkJoinContext.setForkJoinPool(pool);
049  *
050  *         // Set the concurrence context to use by the javolution context.
051  *         ConcurentContext.setContext(ForkJoinContext.class);
052  *
053  *         // Execute some task concurrently.
054  *         ConcurentContext.enter()
055  *         try {
056  *             ConcurrentContext.execute(...);
057  *             ConcurrentContext.execute(...);
058  *         } finally {
059  *             ConcurrentContext.exit();
060  *         }
061  *     }
062  * }
063  * [/code]
064  *
065  * A more convenient way for using the {@code ForkJoinContext} allows the
066  {@link Concurrency} class.
067  *
068  @see Concurrency
069  *
070  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
071  @since 1.0
072  @version 1.0 &mdash; <em>$Date: 2014-02-15 $</em>
073  */
074 public final class ForkJoinContext extends ConcurrentContext {
075 
076     private static final long serialVersionUID = 1L;
077 
078     private final static AtomicReference<ForkJoinPool> _POOL = new AtomicReference<>();
079 
080     private final FastList<Future<?>> _futures = new FastList<>(10);
081 
082     ForkJoinContext() {
083     }
084 
085     /**
086      * Deprecated for fixing typo in method name.
087      *
088      @see #setForkJoinPool(ForkJoinPool)
089      *
090      @deprecated Fixing typo, use {@link #setForkJoinPool(ForkJoinPool)}
091      *             instead.
092      */
093     @Deprecated
094     public static boolean setForkkJoinPool(final ForkJoinPool pool) {
095         return setForkJoinPool(pool);
096     }
097 
098     /**
099      * Set the fork-join-pool used by this context. This method doesn't replace
100      * an already set {@link ForkJoinPool}. Before the <i>context</i> can be
101      * used a {@link ForkJoinPool} must be set.
102      *
103      @param pool the fork-join-pool to use.
104      @return {@code true} if the given pool has been set, {@code false}
105      *          otherwise.
106      @throws NullPointerException if the pool is {@code null}.
107      */
108     public static boolean setForkJoinPool(final ForkJoinPool pool) {
109         return _POOL.compareAndSet(null, requireNonNull(pool, "ForkJoinPool"));
110     }
111 
112     /**
113      * Return the current fork-join-pool used by this context.
114      *
115      @return the current fork-join-pool used by this context. Can be
116      *          {@code null} if not set jet.
117      */
118     public static ForkJoinPool getForkJoinPool() {
119         return _POOL.get();
120     }
121 
122     @Override
123     protected void enterAction() {
124         if (_POOL.get() == null) {
125             throw new IllegalStateException("No ForkJoinPool set.");
126         }
127         _futures.clear();
128     }
129 
130     @Override
131     protected void executeAction(final Runnable logic) {
132         _futures.add(_POOL.get().submit(logic));
133     }
134 
135 
136 
137     @Override
138     protected void exitAction() {
139         try {
140             for (FastList.Node<Future<?>> n = _futures.head(),
141                 end = _futures.tail()(n = n.getNext()) != end;)
142             {
143                 n.getValue().get();
144             }
145         catch (InterruptedException | ExecutionException e) {
146             throw (CancellationException)new CancellationException().initCause(e);
147         }
148     }
149 
150     static {
151         ObjectFactory.setInstance(
152             new ObjectFactory<ForkJoinContext>() {
153                 @Override protected ForkJoinContext create() {
154                     return new ForkJoinContext();
155                 }
156             },
157             ForkJoinContext.class
158         );
159     }
160 
161 }