View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.analysis.integration.gauss;
23  
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.concurrent.ArrayBlockingQueue;
27  import java.util.concurrent.Callable;
28  import java.util.concurrent.ExecutionException;
29  import java.util.concurrent.Future;
30  import java.util.concurrent.ThreadPoolExecutor;
31  import java.util.concurrent.TimeUnit;
32  import java.util.concurrent.atomic.AtomicInteger;
33  
34  import org.hipparchus.util.Pair;
35  import org.junit.Assert;
36  import org.junit.Test;
37  
38  /**
39   * Test for {@link AbstractRuleFactory}.
40   *
41   */
42  public class RuleFactoryTest {
43      /**
44       * Tests that a given rule rule will be computed and added once to the cache
45       * whatever the number of times this rule is called concurrently.
46       */
47      @Test
48          public void testConcurrentCreation() throws InterruptedException,
49                                                      ExecutionException {
50          // Number of times the same rule will be called.
51          final int numTasks = 20;
52  
53          final ThreadPoolExecutor exec
54              = new ThreadPoolExecutor(3, numTasks, 1, TimeUnit.SECONDS,
55                                       new ArrayBlockingQueue<Runnable>(2));
56  
57          final List<Future<Pair<double[], double[]>>> results
58              = new ArrayList<Future<Pair<double[], double[]>>>();
59          for (int i = 0; i < numTasks; i++) {
60              results.add(exec.submit(new RuleBuilder()));
61          }
62  
63          // Ensure that all computations have completed.
64          for (Future<Pair<double[], double[]>> f : results) {
65              f.get();
66          }
67  
68          // Assertion would fail if "getRuleInternal" were not "synchronized".
69          final int n = RuleBuilder.getNumberOfCalls();
70          Assert.assertEquals("Rule computation was called " + n + " times", 1, n);
71      }
72  
73      private static class RuleBuilder implements Callable<Pair<double[], double[]>> {
74          private static final DummyRuleFactory factory = new DummyRuleFactory();
75  
76          public Pair<double[], double[]> call() {
77              final int dummy = 2; // Always request the same rule.
78              return factory.getRule(dummy);
79          }
80  
81          public static int getNumberOfCalls() {
82              return factory.getNumberOfCalls();
83          }
84      }
85  
86      private static class DummyRuleFactory extends AbstractRuleFactory {
87          /** Rule computations counter. */
88          private static AtomicInteger nCalls = new AtomicInteger();
89  
90          @Override
91          protected Pair<double[], double[]> computeRule(int order) {
92              // Tracks whether this computation has been called more than once.
93              nCalls.getAndIncrement();
94  
95              try {
96                  // Sleep to simulate computation time.
97                  Thread.sleep(20);
98              } catch (InterruptedException e) {
99                  Assert.fail("Unexpected interruption");
100             }
101 
102             // Dummy rule (but contents must exist).
103             final double[] p = new double[order];
104             final double[] w = new double[order];
105             for (int i = 0; i < order; i++) {
106                 p[i] = Double.valueOf(i);
107                 w[i] = Double.valueOf(i);
108             }
109             return new Pair<>(p, w);
110         }
111 
112         public int getNumberOfCalls() {
113             return nCalls.get();
114         }
115 
116     }
117 
118 }
119