All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javolution.context.ConcurrentContext Maven / Gradle / Ivy

The newest version!
/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2012 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution.context;

import javolution.lang.Configurable;
import javolution.lang.MathLib;
import javolution.osgi.internal.OSGiServices;

/**
 * 

A context able to take advantage of concurrent algorithms on * multi-processors systems.

* *

When a thread enters a concurrent context, it may performs concurrent * executions by calling the {@link #execute(Runnable)} static method. * The logic is then executed by a concurrent thread or by the current * thread itself if there is no concurrent thread immediately available * (the number of concurrent threads is limited, see {@link #CONCURRENCY}). * [code] * ConcurrentContext ctx = ConcurrentContext.enter(); * try { * ctx.execute(new Runnable() {...}); * ctx.execute(new Runnable() {...}); * } finally { * ctx.exit(); // Waits for all concurrent executions to complete. * // Re-exports any exception raised during concurrent executions. * }[/code]

* *

or equivalent shorter notation: * [code] * ConcurrentContext.execute(new Runnable() {...}, new Runnable() {...});[/code]

* *

Only after all concurrent executions are completed, is the current * thread allowed to exit the scope of the concurrent context * (internal synchronization).

* *

Concurrent logics always execute within the same {@link AbstractContext * context} as the calling thread.

* *

Concurrent contexts ensure the same behavior whether or not the execution * is performed by the current thread or a concurrent thread. Any error or * runtime exception raised during the concurrent logic executions is * propagated to the current thread.

* *

Concurrent contexts are easy to use, and provide automatic * load-balancing between processors with almost no overhead. * Here is a concurrent/recursive quick/merge sort using anonymous inner * classes. * [code] * static void concurrentSort(final FastTable table) { * final int size = table.size(); * if (size < 100) { * table.sort(); // Direct quick sort. * } else { * // Splits table in two and sort both part concurrently. * final FastTable t1 = new FastTable(); * final FastTable t2 = new FastTable(); * ConcurrentContext ctx = ConcurrentContext.enter(); * try { * ctx.execute(new Runnable() { * public void run() { * t1.addAll(table.subList(0, size / 2)); * concurrentSort(t1); // Recursive. * } * }); * ctx.execute(new Runnable() { * public void run() { * t2.addAll(table.subList(size / 2, size)); * concurrentSort(t2); // Recursive. * } * }); * } finally { * ctx.exit(); // Joins. * } * // Merges results. * for (int i=0, i1=0, i2=0; i < size; i++) { * if (i1 >= t1.size()) { * table.set(i, t2.get(i2++)); * } else if (i2 >= t2.size()) { * table.set(i, t1.get(i1++)); * } else { * Comparable o1 = t1.get(i1); * Comparable o2 = t2.get(i2); * if (o1.compareTo(o2) < 0) { * table.set(i, o1); * i1++; * } else { * table.set(i, o2); * i2++; * } * } * } * } * }[/code]

* *

Here is another example using {@link #execute(java.lang.Runnable[]) * execute(Runnable ...)} static method * (Karatsuba recursive multiplication for large integers). * [code] * public LargeInteger multiply(LargeInteger that) { * if (that._size <= 1) { * return multiply(that.longValue()); // Direct multiplication. * } else { // Karatsuba multiplication in O(n^log2(3)) * int bitLength = this.bitLength(); * int n = (bitLength >> 1) + (bitLength & 1); * * // this = a + 2^n b, that = c + 2^n d * LargeInteger b = this.shiftRight(n); * LargeInteger a = this.minus(b.shiftLeft(n)); * LargeInteger d = that.shiftRight(n); * LargeInteger c = that.minus(d.shiftLeft(n)); * Multiply ac = new Multiply(a, c); * Multiply bd = new Multiply(b, d); * Multiply abcd = new Multiply(a.plus(b), c.plus(d)); * ConcurrentContext.execute(ac, bd, abcd); // Convenience method. * // a*c + ((a+b)*(c+d)-a*c-b*d) 2^n + b*d 2^2n * return ac.result.plus(abcd.result.minus(ac.result.plus(bd.result)).shiftWordLeft(n)) * .plus(bd.result.shiftWordLeft(n << 1)); * } * } * private static class Multiply implements Runnable { * LargeInteger left, right, result; * Multiply(LargeInteger left, LargeInteger right) { * this.left = left; * this.right = right; * } * public void run() { * result = left.times(right); // Recursive. * } * }[/code]

* *

Concurrency can be adjusted or disabled. The default concurrency * is defined by the {@link #CONCURRENCY} configurable. * [code] * ConcurrentContext ctx = ConcurrentContext.enter(); * try { * ctx.setConcurrency(0); // Disables concurrency * runAnalysis(); // Performs analysis sequentially. * } finally { * ctx.exit(); // Back to previous concurrency settings. * }[/code]

* * @author Jean-Marie Dautelle * @version 6.0 December 12, 2012 */ public abstract class ConcurrentContext extends AbstractContext { /** * Holds the maximum concurrency * (default Runtime.getRuntime().availableProcessors() - 1). * The maximum concurrency is configurable. For example, the JVM option * {@code -Djavolution.context.ConcurrentContext#CONCURRENCY=0} * disables concurrency. */ public static final Configurable CONCURRENCY = new Configurable() { @Override protected Integer getDefault() { return Runtime.getRuntime().availableProcessors() - 1; } @Override protected Integer initialized(Integer value) { return MathLib.min(value, 65536); // Hard-limiting } @Override protected Integer reconfigured(Integer oldCount, Integer newCount) { throw new UnsupportedOperationException( "Concurrency reconfiguration not supported."); } }; /** * Default constructor. */ protected ConcurrentContext() {} /** * Enters and returns a new concurrent context instance. */ public static ConcurrentContext enter() { ConcurrentContext ctx = current(ConcurrentContext.class); if (ctx == null) { // Root. ctx = OSGiServices.getConcurrentContext(); } return (ConcurrentContext) ctx.enterInner(); } /** * Convenience method to executes the specified logics concurrently. * This method is equivalent to: * [code] * ConcurrentContext ctx = ConcurrentContext.enter(); * try { * ctx.execute(logics[0]); * ctx.execute(logics[1]); * ... * } finally { * ctx.exit(); * }[/code] * * @param logics the logics to execute concurrently if possible. */ public static void execute(Runnable... logics) { ConcurrentContext ctx = ConcurrentContext.enter(); try { for (Runnable logic : logics) { ctx.execute(logic); } } finally { ctx.exit(); } } /** * Executes the specified logic by a concurrent thread if * one available; otherwise the logic is executed by the current thread. * Any exception or error occurring during the concurrent execution is * propagated to the current thread upon exit of the concurrent context. * * @param logic the logic to be executed concurrently when possible. */ public abstract void execute(Runnable logic); /** * Sets the maximum concurrency. Setting a value greater than the * {@link #getConcurrency() current concurrency} has no effect * (concurrency can only be reduced). */ public abstract void setConcurrency(int concurrency); /** * Returns the current concurrency which is basically the number of * concurrent threads authorized to do concurrent work (on top of all * others threads of course). */ public abstract int getConcurrency(); /** * Exits the scope of this concurrent context; this method blocks until * all the concurrent executions are completed. * * @throws RuntimeException re-exports any exception raised during concurrent * executions. * @throws Error re-exports any error raised during concurrent executions. * @throws IllegalStateException if this context is not the current * context. */ @Override public void exit() { // Redefine here for documentation purpose. super.exit(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy