13 |
|
import java.util.concurrent.ExecutionException; |
14 |
|
import java.util.concurrent.ForkJoinPool; |
15 |
|
import java.util.concurrent.ForkJoinTask; |
16 |
+ |
import java.util.concurrent.ThreadLocalRandom; |
17 |
|
import java.util.concurrent.TimeoutException; |
18 |
|
import java.util.concurrent.atomic.AtomicInteger; |
19 |
|
import java.util.concurrent.atomic.AtomicReference; |
20 |
+ |
import java.util.function.BiConsumer; |
21 |
+ |
import java.util.function.Consumer; |
22 |
|
|
23 |
|
import junit.framework.Test; |
24 |
|
import junit.framework.TestSuite; |
338 |
|
public void testSetPendingCount() { |
339 |
|
NoopCC a = new NoopCC(); |
340 |
|
assertEquals(0, a.getPendingCount()); |
341 |
< |
for (int val : new int[] { -1, 0, 1, Integer.MIN_VALUE, Integer.MAX_VALUE }) { |
341 |
> |
int[] vals = { |
342 |
> |
-1, 0, 1, |
343 |
> |
Integer.MIN_VALUE, |
344 |
> |
Integer.MAX_VALUE, |
345 |
> |
}; |
346 |
> |
for (int val : vals) { |
347 |
|
a.setPendingCount(val); |
348 |
|
assertEquals(val, a.getPendingCount()); |
349 |
|
} |
359 |
|
assertEquals(1, a.getPendingCount()); |
360 |
|
a.addToPendingCount(27); |
361 |
|
assertEquals(28, a.getPendingCount()); |
362 |
+ |
a.addToPendingCount(-28); |
363 |
+ |
assertEquals(0, a.getPendingCount()); |
364 |
|
} |
365 |
|
|
366 |
|
/** |
502 |
|
} |
503 |
|
|
504 |
|
/** |
505 |
< |
* quietlyCompleteRoot completes root task |
505 |
> |
* quietlyCompleteRoot completes root task and only root task |
506 |
|
*/ |
507 |
|
public void testQuietlyCompleteRoot() { |
508 |
|
NoopCC a = new NoopCC(); |
1845 |
|
testInvokeOnPool(singletonPool(), a); |
1846 |
|
} |
1847 |
|
|
1848 |
+ |
/** CountedCompleter class javadoc code sample, version 1. */ |
1849 |
+ |
public static <E> void forEach1(E[] array, Consumer<E> action) { |
1850 |
+ |
class Task extends CountedCompleter<Void> { |
1851 |
+ |
final int lo, hi; |
1852 |
+ |
Task(Task parent, int lo, int hi) { |
1853 |
+ |
super(parent); this.lo = lo; this.hi = hi; |
1854 |
+ |
} |
1855 |
+ |
|
1856 |
+ |
public void compute() { |
1857 |
+ |
if (hi - lo >= 2) { |
1858 |
+ |
int mid = (lo + hi) >>> 1; |
1859 |
+ |
// must set pending count before fork |
1860 |
+ |
setPendingCount(2); |
1861 |
+ |
new Task(this, mid, hi).fork(); // right child |
1862 |
+ |
new Task(this, lo, mid).fork(); // left child |
1863 |
+ |
} |
1864 |
+ |
else if (hi > lo) |
1865 |
+ |
action.accept(array[lo]); |
1866 |
+ |
tryComplete(); |
1867 |
+ |
} |
1868 |
+ |
} |
1869 |
+ |
new Task(null, 0, array.length).invoke(); |
1870 |
+ |
} |
1871 |
+ |
|
1872 |
+ |
/** CountedCompleter class javadoc code sample, version 2. */ |
1873 |
+ |
public static <E> void forEach2(E[] array, Consumer<E> action) { |
1874 |
+ |
class Task extends CountedCompleter<Void> { |
1875 |
+ |
final int lo, hi; |
1876 |
+ |
Task(Task parent, int lo, int hi) { |
1877 |
+ |
super(parent); this.lo = lo; this.hi = hi; |
1878 |
+ |
} |
1879 |
+ |
|
1880 |
+ |
public void compute() { |
1881 |
+ |
if (hi - lo >= 2) { |
1882 |
+ |
int mid = (lo + hi) >>> 1; |
1883 |
+ |
setPendingCount(1); // looks off by one, but correct! |
1884 |
+ |
new Task(this, mid, hi).fork(); // right child |
1885 |
+ |
new Task(this, lo, mid).compute(); // direct invoke |
1886 |
+ |
} else { |
1887 |
+ |
if (hi > lo) |
1888 |
+ |
action.accept(array[lo]); |
1889 |
+ |
tryComplete(); |
1890 |
+ |
} |
1891 |
+ |
} |
1892 |
+ |
} |
1893 |
+ |
new Task(null, 0, array.length).invoke(); |
1894 |
+ |
} |
1895 |
+ |
|
1896 |
+ |
/** CountedCompleter class javadoc code sample, version 3. */ |
1897 |
+ |
public static <E> void forEach3(E[] array, Consumer<E> action) { |
1898 |
+ |
class Task extends CountedCompleter<Void> { |
1899 |
+ |
final int lo, hi; |
1900 |
+ |
Task(Task parent, int lo, int hi) { |
1901 |
+ |
super(parent); this.lo = lo; this.hi = hi; |
1902 |
+ |
} |
1903 |
+ |
|
1904 |
+ |
public void compute() { |
1905 |
+ |
int n = hi - lo; |
1906 |
+ |
for (; n >= 2; n /= 2) { |
1907 |
+ |
addToPendingCount(1); |
1908 |
+ |
new Task(this, lo + n/2, lo + n).fork(); |
1909 |
+ |
} |
1910 |
+ |
if (n > 0) |
1911 |
+ |
action.accept(array[lo]); |
1912 |
+ |
propagateCompletion(); |
1913 |
+ |
} |
1914 |
+ |
} |
1915 |
+ |
new Task(null, 0, array.length).invoke(); |
1916 |
+ |
} |
1917 |
+ |
|
1918 |
+ |
/** CountedCompleter class javadoc code sample, version 4. */ |
1919 |
+ |
public static <E> void forEach4(E[] array, Consumer<E> action) { |
1920 |
+ |
class Task extends CountedCompleter<Void> { |
1921 |
+ |
final int lo, hi; |
1922 |
+ |
Task(Task parent, int lo, int hi) { |
1923 |
+ |
super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo)); |
1924 |
+ |
this.lo = lo; this.hi = hi; |
1925 |
+ |
} |
1926 |
+ |
|
1927 |
+ |
public void compute() { |
1928 |
+ |
for (int n = hi - lo; n >= 2; n /= 2) |
1929 |
+ |
new Task(this, lo + n/2, lo + n).fork(); |
1930 |
+ |
action.accept(array[lo]); |
1931 |
+ |
propagateCompletion(); |
1932 |
+ |
} |
1933 |
+ |
} |
1934 |
+ |
if (array.length > 0) |
1935 |
+ |
new Task(null, 0, array.length).invoke(); |
1936 |
+ |
} |
1937 |
+ |
|
1938 |
+ |
void testRecursiveDecomposition( |
1939 |
+ |
BiConsumer<Integer[], Consumer<Integer>> action) { |
1940 |
+ |
int n = ThreadLocalRandom.current().nextInt(8); |
1941 |
+ |
Integer[] a = new Integer[n]; |
1942 |
+ |
for (int i = 0; i < n; i++) a[i] = i + 1; |
1943 |
+ |
AtomicInteger ai = new AtomicInteger(0); |
1944 |
+ |
action.accept(a, (x) -> ai.addAndGet(x)); |
1945 |
+ |
assertEquals(n * (n + 1) / 2, ai.get()); |
1946 |
+ |
} |
1947 |
+ |
|
1948 |
+ |
/** |
1949 |
+ |
* Variants of divide-by-two recursive decomposition into leaf tasks, |
1950 |
+ |
* as described in the CountedCompleter class javadoc code samples |
1951 |
+ |
*/ |
1952 |
+ |
public void testRecursiveDecomposition() { |
1953 |
+ |
testRecursiveDecomposition(CountedCompleterTest::forEach1); |
1954 |
+ |
testRecursiveDecomposition(CountedCompleterTest::forEach2); |
1955 |
+ |
testRecursiveDecomposition(CountedCompleterTest::forEach3); |
1956 |
+ |
testRecursiveDecomposition(CountedCompleterTest::forEach4); |
1957 |
+ |
} |
1958 |
+ |
|
1959 |
|
} |