Concurrency.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 java.util.Properties;
023 import java.util.concurrent.ForkJoinPool;
024 
025 import javolution.context.ConcurrentContext;
026 import javolution.context.Context;
027 import javolution.context.LogContext;
028 import javolution.lang.Configurable;
029 
030 /**
031  * Simplify the usage of the {@link ConcurrentContext} usage by using the the
032  * Java 'try' for resources capability.
033  <p/>
034  * Normally you will write
035  * [code]
036  * ConcurrentContext.enter();
037  * try {
038  *     ConcurrentContext.execute(task1);
039  *     ConcurrentContext.execute(task2); }
040  * } finally {
041  *     ConcurrentContext.exit();
042  * }
043  * [/code]
044  * to execute two tasks. By using this class you can shorten the code to be
045  * written to:
046  * [code]
047  * try (Concurrency c = Concurrency.start()) {
048  *     c.execute(task1);
049  *     c.execute(task2);
050  * }
051  * [/code]
052  *
053  * The configuration is performed as followed, before executing any concurrent
054  * code.
055  * [code]
056  * public class Main {
057  *     public static void main(final String[] args) {
058  *         // Using 10 threads for evolving.
059  *         Concurrency.setConcurrency(9);
060  *
061  *         // Forces the application only to use one thread.
062  *         Concurrency.setConcurrency(0);
063  *     }
064  * }
065  * [/code]
066  *
067  * The {@code ConcurrentContext} from the <i>JScience</i> project uses it's
068  * own--optimized--thread-pool implementation. If you need to have a single
069  * executor service, for the GA and your own classes, you can initialize the
070  * {@code Concurrency} class with the {@link ForkJoinPool} from the JDK.
071  *
072  * [code]
073  * public class Main {
074  *     public static void main(final String[] args) {
075  *         final int nthreads = 10;
076  *         final ForkJoinPool pool = new ForkJoinPool(nthreads);
077  *         Concurrency.setForkJoinPool(pool);
078  *         ...
079  *     }
080  * }
081  * [/code]
082  *
083  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
084  @since 1.0
085  @version 1.0 &mdash; <em>$Date: 2013-12-18 $</em>
086  */
087 public final class Concurrency implements AutoCloseable {
088 
089     private static final String KEY_CONTEXT =
090         "javolution.context.ConcurrentContext#DEFAULT";
091 
092     private static final String KEY_CONCURRENTCY =
093         "javolution.context.ConcurrentContext#MAXIMUM_CONCURRENCY";
094 
095     private static final Concurrency INSTANCE = new Concurrency();
096 
097     private Concurrency() {
098     }
099 
100     /**
101      * Set the number of threads to use by the {@link ConcurrentContext}.
102      *
103      @param concurrency the number of threads to use for the default concurrent
104      *        context.
105      */
106     public static void setConcurrency(final int concurrency) {
107         if (concurrency > ConcurrentContext.getConcurrency()) {
108             final Properties properties = new Properties();
109             properties.put(KEY_CONCURRENTCY, concurrency);
110             setProperties(properties);
111         }
112 
113         ConcurrentContext.setConcurrency(concurrency);
114     }
115 
116     /**
117      * Set the concurrent-context to be used by the concurrency.
118      *
119      @param type  the concurrent-context type.
120      @throws NullPointerException if the given {@code type} is {@code null}.
121      */
122     public static void setContext(final Class<? extends ConcurrentContext> type) {
123         final Properties properties = new Properties();
124         properties.put(KEY_CONTEXT, type);
125         setProperties(properties);
126     }
127 
128     /**
129      * Convenience method for setting the {@link ForkJoinPool} and the concurrent
130      * context to {@link ForkJoinContext}.
131      *
132      @param pool the {@link ForkJoinPool} to use for concurrency.
133      */
134     public static void setForkJoinPool(final ForkJoinPool pool) {
135         ForkJoinContext.setForkJoinPool(pool);
136         setContext(ForkJoinContext.class);
137     }
138 
139     private static void setProperties(final Properties properties) {
140         Context.enter(LogContext.NULL);
141         try {
142             Configurable.read(properties);
143         finally {
144             Context.exit();
145         }
146     }
147 
148     /**
149      * Reset to the default default context.
150      */
151     public static void setDefaultContext() {
152         setContext(ConcurrentContext.DEFAULT.get());
153     }
154 
155     @SuppressWarnings("unchecked")
156     public static Class<ConcurrentContext> getContext() {
157         final Context context = Context.getCurrent();
158         return (Class<ConcurrentContext>)
159                 ConcurrentContext.class.cast(context).getClass();
160     }
161 
162     public static Concurrency start() {
163         ConcurrentContext.enter();
164         return INSTANCE;
165     }
166 
167     @SuppressWarnings("static-method")
168     public void execute(final Runnable task) {
169         ConcurrentContext.execute(task);
170     }
171 
172     @Override
173     public void close() {
174         ConcurrentContext.exit();
175     }
176 
177 }