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.Binary64;
35  import org.hipparchus.util.Binary64Field;
36  import org.hipparchus.util.Pair;
37  import org.junit.Assert;
38  import org.junit.Test;
39  
40  /**
41   * Test for {@link FieldAbstractRuleFactory}.
42   *
43   */
44  public class FieldRuleFactoryTest {
45      /**
46       * Tests that a given rule rule will be computed and added once to the cache
47       * whatever the number of times this rule is called concurrently.
48       */
49      @Test
50          public void testConcurrentCreation() throws InterruptedException,
51                                                      ExecutionException {
52          // Number of times the same rule will be called.
53          final int numTasks = 20;
54  
55          final ThreadPoolExecutor exec
56              = new ThreadPoolExecutor(3, numTasks, 1, TimeUnit.SECONDS,
57                                       new ArrayBlockingQueue<Runnable>(2));
58  
59          final List<Future<Pair<Binary64[], Binary64[]>>> results
60              = new ArrayList<Future<Pair<Binary64[], Binary64[]>>>();
61          for (int i = 0; i < numTasks; i++) {
62              results.add(exec.submit(new RuleBuilder()));
63          }
64  
65          // Ensure that all computations have completed.
66          for (Future<Pair<Binary64[], Binary64[]>> f : results) {
67              f.get();
68          }
69  
70          // Assertion would fail if "getRuleInternal" were not "synchronized".
71          final int n = RuleBuilder.getNumberOfCalls();
72          Assert.assertEquals("Rule computation was called " + n + " times", 1, n);
73      }
74  
75      private static class RuleBuilder implements Callable<Pair<Binary64[], Binary64[]>> {
76          private static final DummyRuleFactory factory = new DummyRuleFactory();
77  
78          public Pair<Binary64[], Binary64[]> call() {
79              final int dummy = 2; // Always request the same rule.
80              return factory.getRule(dummy);
81          }
82  
83          public static int getNumberOfCalls() {
84              return factory.getNumberOfCalls();
85          }
86      }
87  
88      private static class DummyRuleFactory extends FieldAbstractRuleFactory<Binary64> {
89          /** Rule computations counter. */
90          private static AtomicInteger nCalls = new AtomicInteger();
91  
92          
93          DummyRuleFactory() {
94              super(Binary64Field.getInstance());
95          }
96  
97          @Override
98          protected Pair<Binary64[], Binary64[]> computeRule(int order) {
99              // Tracks whether this computation has been called more than once.
100             nCalls.getAndIncrement();
101 
102             try {
103                 // Sleep to simulate computation time.
104                 Thread.sleep(20);
105             } catch (InterruptedException e) {
106                 Assert.fail("Unexpected interruption");
107             }
108 
109             // Dummy rule (but contents must exist).
110             final Binary64[] p = new Binary64[order];
111             final Binary64[] w = new Binary64[order];
112             for (int i = 0; i < order; i++) {
113                 p[i] = new Binary64(i);
114                 w[i] = new Binary64(i);
115             }
116             return new Pair<>(p, w);
117         }
118 
119         public int getNumberOfCalls() {
120             return nCalls.get();
121         }
122 
123     }
124 
125 }