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