code: @Override
  	public RandomVariableInterface getValue(final double evaluationTime, final MonteCarloSimulationInterface model) throws CalculationException {
  
  		if(products == null || products.length == 0) {
  			return null;
  		}
  
  		// We do not allocate more threads the twice the number of processors.
  		int numberOfThreads = Math.min(Math.max(2 * Runtime.getRuntime().availableProcessors(),1),products.length);
  		ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
  
  		RandomVariableInterface value = null;
  		try {
  			// Start calculation threads for each product
  			Vector<Future<RandomVariableInterface>> values = new Vector<Future<RandomVariableInterface>>(products.length);
  			for(int i=0; i<products.length; i++) {
  				final AbstractMonteCarloProduct product = products[i];
  				final double weight = weights[i];
  
  				Callable<RandomVariableInterface> worker = new  Callable<RandomVariableInterface>() {
  					public RandomVariableInterface call() throws CalculationException {
  						return product.getValue(evaluationTime, model).mult(weight);
  					}
  				};
  				executor.submit(worker);
  			}
  
  			// Collect and sum results
  			value = values.get(0).get();
  			for(int i=1; i<products.length; i++) {
  				value = value.add(values.get(i).get());
  			}
  		} catch (InterruptedException e) {
  			e.printStackTrace();
  		} catch (ExecutionException e) {
  			e.printStackTrace();
  		} finally {
  			executor.shutdown();
  		}
  
  		return value;
  	}
docs: /* (non-Javadoc)
  @see net.finmath.montecarlo.AbstractMonteCarloProduct#getValue(double, net.finmath.montecarlo.MonteCarloSimulationInterface)