10888a09821a98ac0680fad765217302858e70fa4Paul Duffin/* 20888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Copyright (C) 2013 The Guava Authors 30888a09821a98ac0680fad765217302858e70fa4Paul Duffin * 40888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 50888a09821a98ac0680fad765217302858e70fa4Paul Duffin * you may not use this file except in compliance with the License. 60888a09821a98ac0680fad765217302858e70fa4Paul Duffin * You may obtain a copy of the License at 70888a09821a98ac0680fad765217302858e70fa4Paul Duffin * 80888a09821a98ac0680fad765217302858e70fa4Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 90888a09821a98ac0680fad765217302858e70fa4Paul Duffin * 100888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Unless required by applicable law or agreed to in writing, software 110888a09821a98ac0680fad765217302858e70fa4Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 120888a09821a98ac0680fad765217302858e70fa4Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130888a09821a98ac0680fad765217302858e70fa4Paul Duffin * See the License for the specific language governing permissions and 140888a09821a98ac0680fad765217302858e70fa4Paul Duffin * limitations under the License. 150888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 160888a09821a98ac0680fad765217302858e70fa4Paul Duffin 170888a09821a98ac0680fad765217302858e70fa4Paul Duffinpackage com.google.common.util.concurrent; 180888a09821a98ac0680fad765217302858e70fa4Paul Duffin 193ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport static com.google.common.util.concurrent.MoreExecutors.directExecutor; 203ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin 210888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.AfterExperiment; 220888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.BeforeExperiment; 230888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.Benchmark; 240888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.Param; 250888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.api.Footprint; 260888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.api.VmOptions; 270888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.base.Preconditions; 280888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.Lists; 290888a09821a98ac0680fad765217302858e70fa4Paul Duffin 300888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.Queue; 310888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.ArrayBlockingQueue; 320888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.CountDownLatch; 330888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.Executor; 340888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.ExecutorService; 350888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.ThreadPoolExecutor; 360888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.TimeUnit; 370888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.atomic.AtomicInteger; 380888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.logging.Level; 390888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.logging.Logger; 400888a09821a98ac0680fad765217302858e70fa4Paul Duffin 410888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport javax.annotation.Nullable; 420888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport javax.annotation.concurrent.GuardedBy; 430888a09821a98ac0680fad765217302858e70fa4Paul Duffin 440888a09821a98ac0680fad765217302858e70fa4Paul Duffin/** 450888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Benchmarks for {@link ExecutionList}. 460888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 470888a09821a98ac0680fad765217302858e70fa4Paul Duffin@VmOptions({"-Xms3g", "-Xmx3g"}) 480888a09821a98ac0680fad765217302858e70fa4Paul Duffinpublic class ExecutionListBenchmark { 490888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final int NUM_THREADS = 10; // make a param? 500888a09821a98ac0680fad765217302858e70fa4Paul Duffin 510888a09821a98ac0680fad765217302858e70fa4Paul Duffin // simple interface to wrap our two implementations. 520888a09821a98ac0680fad765217302858e70fa4Paul Duffin interface ExecutionListWrapper { 530888a09821a98ac0680fad765217302858e70fa4Paul Duffin void add(Runnable runnable, Executor executor); 540888a09821a98ac0680fad765217302858e70fa4Paul Duffin void execute(); 550888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** Returns the underlying implementation, useful for the Footprint benchmark. */ 560888a09821a98ac0680fad765217302858e70fa4Paul Duffin Object getImpl(); 570888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 580888a09821a98ac0680fad765217302858e70fa4Paul Duffin 590888a09821a98ac0680fad765217302858e70fa4Paul Duffin enum Impl { 600888a09821a98ac0680fad765217302858e70fa4Paul Duffin NEW { 610888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override ExecutionListWrapper newExecutionList() { 620888a09821a98ac0680fad765217302858e70fa4Paul Duffin return new ExecutionListWrapper() { 630888a09821a98ac0680fad765217302858e70fa4Paul Duffin final ExecutionList list = new ExecutionList(); 640888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void add(Runnable runnable, Executor executor) { 650888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.add(runnable, executor); 660888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 670888a09821a98ac0680fad765217302858e70fa4Paul Duffin 680888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void execute() { 690888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 700888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 710888a09821a98ac0680fad765217302858e70fa4Paul Duffin 720888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Object getImpl() { 730888a09821a98ac0680fad765217302858e70fa4Paul Duffin return list; 740888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 750888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 760888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 770888a09821a98ac0680fad765217302858e70fa4Paul Duffin }, 780888a09821a98ac0680fad765217302858e70fa4Paul Duffin NEW_WITH_CAS { 790888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override ExecutionListWrapper newExecutionList() { 800888a09821a98ac0680fad765217302858e70fa4Paul Duffin return new ExecutionListWrapper() { 810888a09821a98ac0680fad765217302858e70fa4Paul Duffin final ExecutionListCAS list = new ExecutionListCAS(); 820888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void add(Runnable runnable, Executor executor) { 830888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.add(runnable, executor); 840888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 850888a09821a98ac0680fad765217302858e70fa4Paul Duffin 860888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void execute() { 870888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 880888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 890888a09821a98ac0680fad765217302858e70fa4Paul Duffin 900888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Object getImpl() { 910888a09821a98ac0680fad765217302858e70fa4Paul Duffin return list; 920888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 930888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 940888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 950888a09821a98ac0680fad765217302858e70fa4Paul Duffin }, 960888a09821a98ac0680fad765217302858e70fa4Paul Duffin NEW_WITH_QUEUE { 970888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override ExecutionListWrapper newExecutionList() { 980888a09821a98ac0680fad765217302858e70fa4Paul Duffin return new ExecutionListWrapper() { 990888a09821a98ac0680fad765217302858e70fa4Paul Duffin final NewExecutionListQueue list = new NewExecutionListQueue(); 1000888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void add(Runnable runnable, Executor executor) { 1010888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.add(runnable, executor); 1020888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1040888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void execute() { 1050888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 1060888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1070888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1080888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Object getImpl() { 1090888a09821a98ac0680fad765217302858e70fa4Paul Duffin return list; 1100888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1110888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 1120888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1130888a09821a98ac0680fad765217302858e70fa4Paul Duffin }, 1140888a09821a98ac0680fad765217302858e70fa4Paul Duffin NEW_WITHOUT_REVERSE { 1150888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override ExecutionListWrapper newExecutionList() { 1160888a09821a98ac0680fad765217302858e70fa4Paul Duffin return new ExecutionListWrapper() { 1170888a09821a98ac0680fad765217302858e70fa4Paul Duffin final NewExecutionListWithoutReverse list = new NewExecutionListWithoutReverse(); 1180888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void add(Runnable runnable, Executor executor) { 1190888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.add(runnable, executor); 1200888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1210888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1220888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void execute() { 1230888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 1240888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1250888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1260888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Object getImpl() { 1270888a09821a98ac0680fad765217302858e70fa4Paul Duffin return list; 1280888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1290888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 1300888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1310888a09821a98ac0680fad765217302858e70fa4Paul Duffin }, 1320888a09821a98ac0680fad765217302858e70fa4Paul Duffin OLD { 1330888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override ExecutionListWrapper newExecutionList() { 1340888a09821a98ac0680fad765217302858e70fa4Paul Duffin return new ExecutionListWrapper() { 1350888a09821a98ac0680fad765217302858e70fa4Paul Duffin final OldExecutionList list = new OldExecutionList(); 1360888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void add(Runnable runnable, Executor executor) { 1370888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.add(runnable, executor); 1380888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1390888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1400888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void execute() { 1410888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 1420888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1430888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1440888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Object getImpl() { 1450888a09821a98ac0680fad765217302858e70fa4Paul Duffin return list; 1460888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1470888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 1480888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1490888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 1500888a09821a98ac0680fad765217302858e70fa4Paul Duffin abstract ExecutionListWrapper newExecutionList(); 1510888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1520888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1530888a09821a98ac0680fad765217302858e70fa4Paul Duffin private ExecutorService executorService; 1540888a09821a98ac0680fad765217302858e70fa4Paul Duffin private CountDownLatch listenerLatch; 1550888a09821a98ac0680fad765217302858e70fa4Paul Duffin private ExecutionListWrapper list; 1560888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1570888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Param Impl impl; 1580888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Param({"1", "5", "10"}) int numListeners; 1590888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1600888a09821a98ac0680fad765217302858e70fa4Paul Duffin private final Runnable listener = new Runnable() { 1610888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 1620888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch.countDown(); 1630888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1640888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 1650888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1660888a09821a98ac0680fad765217302858e70fa4Paul Duffin @BeforeExperiment void setUp() throws Exception { 1670888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService = new ThreadPoolExecutor(NUM_THREADS, 1680888a09821a98ac0680fad765217302858e70fa4Paul Duffin NUM_THREADS, 1690888a09821a98ac0680fad765217302858e70fa4Paul Duffin Long.MAX_VALUE, 1700888a09821a98ac0680fad765217302858e70fa4Paul Duffin TimeUnit.SECONDS, 1710888a09821a98ac0680fad765217302858e70fa4Paul Duffin new ArrayBlockingQueue<Runnable>(1000)); 1720888a09821a98ac0680fad765217302858e70fa4Paul Duffin final AtomicInteger integer = new AtomicInteger(); 1730888a09821a98ac0680fad765217302858e70fa4Paul Duffin // Execute a bunch of tasks to ensure that our threads are allocated and hot 1740888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < NUM_THREADS * 10; i++) { 1750888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService.submit(new Runnable() { 1760888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 1770888a09821a98ac0680fad765217302858e70fa4Paul Duffin integer.getAndIncrement(); 1780888a09821a98ac0680fad765217302858e70fa4Paul Duffin }}); 1790888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1800888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1810888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1820888a09821a98ac0680fad765217302858e70fa4Paul Duffin @AfterExperiment void tearDown() throws Exception { 1830888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService.shutdown(); 1840888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1850888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1860888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Footprint(exclude = {Runnable.class, Executor.class}) 1870888a09821a98ac0680fad765217302858e70fa4Paul Duffin public Object measureSize() { 1880888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = impl.newExecutionList(); 1890888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < numListeners; i++) { 1903ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin list.add(listener, directExecutor()); 1910888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1920888a09821a98ac0680fad765217302858e70fa4Paul Duffin return list.getImpl(); 1930888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1940888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1950888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Benchmark int addThenExecute_singleThreaded(int reps) { 1960888a09821a98ac0680fad765217302858e70fa4Paul Duffin int returnValue = 0; 1970888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < reps; i++) { 1980888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = impl.newExecutionList(); 1990888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch = new CountDownLatch(numListeners); 2000888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int j = 0; j < numListeners; j++) { 2013ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin list.add(listener, directExecutor()); 2020888a09821a98ac0680fad765217302858e70fa4Paul Duffin returnValue += listenerLatch.getCount(); 2030888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2040888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 2050888a09821a98ac0680fad765217302858e70fa4Paul Duffin returnValue += listenerLatch.getCount(); 2060888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2070888a09821a98ac0680fad765217302858e70fa4Paul Duffin return returnValue; 2080888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2090888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2100888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Benchmark int executeThenAdd_singleThreaded(int reps) { 2110888a09821a98ac0680fad765217302858e70fa4Paul Duffin int returnValue = 0; 2120888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < reps; i++) { 2130888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = impl.newExecutionList(); 2140888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 2150888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch = new CountDownLatch(numListeners); 2160888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int j = 0; j < numListeners; j++) { 2173ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin list.add(listener, directExecutor()); 2180888a09821a98ac0680fad765217302858e70fa4Paul Duffin returnValue += listenerLatch.getCount(); 2190888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2200888a09821a98ac0680fad765217302858e70fa4Paul Duffin returnValue += listenerLatch.getCount(); 2210888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2220888a09821a98ac0680fad765217302858e70fa4Paul Duffin return returnValue; 2230888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2240888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2250888a09821a98ac0680fad765217302858e70fa4Paul Duffin private final Runnable executeTask = new Runnable() { 2260888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 2270888a09821a98ac0680fad765217302858e70fa4Paul Duffin list.execute(); 2280888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2290888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 2300888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2310888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Benchmark int addThenExecute_multiThreaded(final int reps) throws InterruptedException { 2320888a09821a98ac0680fad765217302858e70fa4Paul Duffin Runnable addTask = new Runnable() { 2330888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 2340888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < numListeners; i++) { 2353ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin list.add(listener, directExecutor()); 2360888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2370888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2380888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 2390888a09821a98ac0680fad765217302858e70fa4Paul Duffin int returnValue = 0; 2400888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < reps; i++) { 2410888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = impl.newExecutionList(); 2420888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch = new CountDownLatch(numListeners * NUM_THREADS); 2430888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int j = 0; j < NUM_THREADS; j++) { 2440888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService.submit(addTask); 2450888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2460888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService.submit(executeTask); 2470888a09821a98ac0680fad765217302858e70fa4Paul Duffin returnValue = (int) listenerLatch.getCount(); 2480888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch.await(); 2490888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2500888a09821a98ac0680fad765217302858e70fa4Paul Duffin return returnValue; 2510888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2520888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Benchmark int executeThenAdd_multiThreaded(final int reps) throws InterruptedException { 2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin Runnable addTask = new Runnable() { 2550888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < numListeners; i++) { 2573ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin list.add(listener, directExecutor()); 2580888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2590888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2600888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 2610888a09821a98ac0680fad765217302858e70fa4Paul Duffin int returnValue = 0; 2620888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int i = 0; i < reps; i++) { 2630888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = impl.newExecutionList(); 2640888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch = new CountDownLatch(numListeners * NUM_THREADS); 2650888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService.submit(executeTask); 2660888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (int j = 0; j < NUM_THREADS; j++) { 2670888a09821a98ac0680fad765217302858e70fa4Paul Duffin executorService.submit(addTask); 2680888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2690888a09821a98ac0680fad765217302858e70fa4Paul Duffin returnValue = (int) listenerLatch.getCount(); 2700888a09821a98ac0680fad765217302858e70fa4Paul Duffin listenerLatch.await(); 2710888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2720888a09821a98ac0680fad765217302858e70fa4Paul Duffin return returnValue; 2730888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2740888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2750888a09821a98ac0680fad765217302858e70fa4Paul Duffin // This is the old implementation of ExecutionList using a LinkedList. 2760888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final class OldExecutionList { 2770888a09821a98ac0680fad765217302858e70fa4Paul Duffin static final Logger log = Logger.getLogger(OldExecutionList.class.getName()); 2780888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Queue<OldExecutionList.RunnableExecutorPair> runnables = Lists.newLinkedList(); 2790888a09821a98ac0680fad765217302858e70fa4Paul Duffin boolean executed = false; 2800888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2810888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void add(Runnable runnable, Executor executor) { 2820888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(runnable, "Runnable was null."); 2830888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(executor, "Executor was null."); 2840888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2850888a09821a98ac0680fad765217302858e70fa4Paul Duffin boolean executeImmediate = false; 2860888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2870888a09821a98ac0680fad765217302858e70fa4Paul Duffin synchronized (runnables) { 2880888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (!executed) { 2890888a09821a98ac0680fad765217302858e70fa4Paul Duffin runnables.add(new RunnableExecutorPair(runnable, executor)); 2900888a09821a98ac0680fad765217302858e70fa4Paul Duffin } else { 2910888a09821a98ac0680fad765217302858e70fa4Paul Duffin executeImmediate = true; 2920888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2930888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2940888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2950888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (executeImmediate) { 2960888a09821a98ac0680fad765217302858e70fa4Paul Duffin new RunnableExecutorPair(runnable, executor).execute(); 2970888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2980888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2990888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3000888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void execute() { 3010888a09821a98ac0680fad765217302858e70fa4Paul Duffin synchronized (runnables) { 3020888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (executed) { 3030888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 3040888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3050888a09821a98ac0680fad765217302858e70fa4Paul Duffin executed = true; 3060888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3070888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3080888a09821a98ac0680fad765217302858e70fa4Paul Duffin while (!runnables.isEmpty()) { 3090888a09821a98ac0680fad765217302858e70fa4Paul Duffin runnables.poll().execute(); 3100888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3110888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3120888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3130888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static class RunnableExecutorPair { 3140888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Runnable runnable; 3150888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Executor executor; 3160888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3170888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair(Runnable runnable, Executor executor) { 3180888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.runnable = runnable; 3190888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.executor = executor; 3200888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3210888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3220888a09821a98ac0680fad765217302858e70fa4Paul Duffin void execute() { 3230888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 3240888a09821a98ac0680fad765217302858e70fa4Paul Duffin executor.execute(runnable); 3250888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (RuntimeException e) { 3260888a09821a98ac0680fad765217302858e70fa4Paul Duffin log.log(Level.SEVERE, "RuntimeException while executing runnable " 3270888a09821a98ac0680fad765217302858e70fa4Paul Duffin + runnable + " with executor " + executor, e); 3280888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3290888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3300888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3310888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3320888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3330888a09821a98ac0680fad765217302858e70fa4Paul Duffin // A version of the execution list that doesn't reverse the stack in execute(). 3340888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final class NewExecutionListWithoutReverse { 3350888a09821a98ac0680fad765217302858e70fa4Paul Duffin static final Logger log = Logger.getLogger(NewExecutionListWithoutReverse.class.getName()); 3360888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3370888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GuardedBy("this") 3380888a09821a98ac0680fad765217302858e70fa4Paul Duffin private RunnableExecutorPair runnables; 3390888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GuardedBy("this") 3400888a09821a98ac0680fad765217302858e70fa4Paul Duffin private boolean executed; 3410888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3420888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void add(Runnable runnable, Executor executor) { 3430888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(runnable, "Runnable was null."); 3440888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(executor, "Executor was null."); 3450888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3460888a09821a98ac0680fad765217302858e70fa4Paul Duffin synchronized (this) { 3470888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (!executed) { 3480888a09821a98ac0680fad765217302858e70fa4Paul Duffin runnables = new RunnableExecutorPair(runnable, executor, runnables); 3490888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 3500888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3510888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3520888a09821a98ac0680fad765217302858e70fa4Paul Duffin executeListener(runnable, executor); 3530888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3540888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3550888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void execute() { 3560888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair list; 3570888a09821a98ac0680fad765217302858e70fa4Paul Duffin synchronized (this) { 3580888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (executed) { 3590888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 3600888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3610888a09821a98ac0680fad765217302858e70fa4Paul Duffin executed = true; 3620888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = runnables; 3630888a09821a98ac0680fad765217302858e70fa4Paul Duffin runnables = null; // allow GC to free listeners even if this stays around for a while. 3640888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3650888a09821a98ac0680fad765217302858e70fa4Paul Duffin while (list != null) { 3660888a09821a98ac0680fad765217302858e70fa4Paul Duffin executeListener(list.runnable, list.executor); 3670888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = list.next; 3680888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3690888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3700888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3710888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static void executeListener(Runnable runnable, Executor executor) { 3720888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 3730888a09821a98ac0680fad765217302858e70fa4Paul Duffin executor.execute(runnable); 3740888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (RuntimeException e) { 3750888a09821a98ac0680fad765217302858e70fa4Paul Duffin log.log(Level.SEVERE, "RuntimeException while executing runnable " 3760888a09821a98ac0680fad765217302858e70fa4Paul Duffin + runnable + " with executor " + executor, e); 3770888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3780888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3790888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3800888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final class RunnableExecutorPair { 3810888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Runnable runnable; 3820888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Executor executor; 3830888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Nullable RunnableExecutorPair next; 3840888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3850888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) { 3860888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.runnable = runnable; 3870888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.executor = executor; 3880888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.next = next; 3890888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3900888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3910888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3920888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3930888a09821a98ac0680fad765217302858e70fa4Paul Duffin // A version of the ExecutionList that uses an explicit tail pointer to keep the nodes in order 3940888a09821a98ac0680fad765217302858e70fa4Paul Duffin // rather than flipping the stack in execute(). 3950888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final class NewExecutionListQueue { 3960888a09821a98ac0680fad765217302858e70fa4Paul Duffin static final Logger log = Logger.getLogger(NewExecutionListQueue.class.getName()); 3970888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3980888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GuardedBy("this") 3990888a09821a98ac0680fad765217302858e70fa4Paul Duffin private RunnableExecutorPair head; 4000888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GuardedBy("this") 4010888a09821a98ac0680fad765217302858e70fa4Paul Duffin private RunnableExecutorPair tail; 4020888a09821a98ac0680fad765217302858e70fa4Paul Duffin @GuardedBy("this") 4030888a09821a98ac0680fad765217302858e70fa4Paul Duffin private boolean executed; 4040888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4050888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void add(Runnable runnable, Executor executor) { 4060888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(runnable, "Runnable was null."); 4070888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(executor, "Executor was null."); 4080888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4090888a09821a98ac0680fad765217302858e70fa4Paul Duffin synchronized (this) { 4100888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (!executed) { 4110888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair newTail = new RunnableExecutorPair(runnable, executor); 4120888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (head == null) { 4130888a09821a98ac0680fad765217302858e70fa4Paul Duffin head = newTail; 4140888a09821a98ac0680fad765217302858e70fa4Paul Duffin tail = newTail; 4150888a09821a98ac0680fad765217302858e70fa4Paul Duffin } else { 4160888a09821a98ac0680fad765217302858e70fa4Paul Duffin tail.next = newTail; 4170888a09821a98ac0680fad765217302858e70fa4Paul Duffin tail = newTail; 4180888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4190888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 4200888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4210888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4220888a09821a98ac0680fad765217302858e70fa4Paul Duffin executeListener(runnable, executor); 4230888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4240888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4250888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void execute() { 4260888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair list; 4270888a09821a98ac0680fad765217302858e70fa4Paul Duffin synchronized (this) { 4280888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (executed) { 4290888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 4300888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4310888a09821a98ac0680fad765217302858e70fa4Paul Duffin executed = true; 4320888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = head; 4330888a09821a98ac0680fad765217302858e70fa4Paul Duffin head = null; // allow GC to free listeners even if this stays around for a while. 4340888a09821a98ac0680fad765217302858e70fa4Paul Duffin tail = null; 4350888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4360888a09821a98ac0680fad765217302858e70fa4Paul Duffin while (list != null) { 4370888a09821a98ac0680fad765217302858e70fa4Paul Duffin executeListener(list.runnable, list.executor); 4380888a09821a98ac0680fad765217302858e70fa4Paul Duffin list = list.next; 4390888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4400888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4410888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4420888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static void executeListener(Runnable runnable, Executor executor) { 4430888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 4440888a09821a98ac0680fad765217302858e70fa4Paul Duffin executor.execute(runnable); 4450888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (RuntimeException e) { 4460888a09821a98ac0680fad765217302858e70fa4Paul Duffin log.log(Level.SEVERE, "RuntimeException while executing runnable " 4470888a09821a98ac0680fad765217302858e70fa4Paul Duffin + runnable + " with executor " + executor, e); 4480888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4490888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4500888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4510888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final class RunnableExecutorPair { 4520888a09821a98ac0680fad765217302858e70fa4Paul Duffin Runnable runnable; 4530888a09821a98ac0680fad765217302858e70fa4Paul Duffin Executor executor; 4540888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Nullable RunnableExecutorPair next; 4550888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4560888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair(Runnable runnable, Executor executor) { 4570888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.runnable = runnable; 4580888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.executor = executor; 4590888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4600888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4610888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4620888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4630888a09821a98ac0680fad765217302858e70fa4Paul Duffin // A version of the list that uses compare and swap to manage the stack without locks. 4640888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final class ExecutionListCAS { 4650888a09821a98ac0680fad765217302858e70fa4Paul Duffin static final Logger log = Logger.getLogger(ExecutionListCAS.class.getName()); 4660888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4670888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final sun.misc.Unsafe UNSAFE; 4680888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final long HEAD_OFFSET; 4690888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4700888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 4710888a09821a98ac0680fad765217302858e70fa4Paul Duffin * A special instance of {@link RunnableExecutorPair} that is used as a sentinel value for the 4720888a09821a98ac0680fad765217302858e70fa4Paul Duffin * bottom of the stack. 4730888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 4740888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final RunnableExecutorPair NULL_PAIR = new RunnableExecutorPair(null, null); 4750888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4760888a09821a98ac0680fad765217302858e70fa4Paul Duffin static { 4770888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 4780888a09821a98ac0680fad765217302858e70fa4Paul Duffin UNSAFE = getUnsafe(); 4790888a09821a98ac0680fad765217302858e70fa4Paul Duffin HEAD_OFFSET = UNSAFE.objectFieldOffset(ExecutionListCAS.class.getDeclaredField("head")); 4800888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (Exception ex) { 4810888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw new Error(ex); 4820888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4830888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4840888a09821a98ac0680fad765217302858e70fa4Paul Duffin 4850888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 4860888a09821a98ac0680fad765217302858e70fa4Paul Duffin * TODO(user): This was copied verbatim from Striped64.java... standardize this? 4870888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 4880888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static sun.misc.Unsafe getUnsafe() { 4890888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 4900888a09821a98ac0680fad765217302858e70fa4Paul Duffin return sun.misc.Unsafe.getUnsafe(); 4910888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (SecurityException tryReflectionInstead) {} 4920888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 4930888a09821a98ac0680fad765217302858e70fa4Paul Duffin return java.security.AccessController.doPrivileged 4940888a09821a98ac0680fad765217302858e70fa4Paul Duffin (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() { 4950888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public sun.misc.Unsafe run() throws Exception { 4960888a09821a98ac0680fad765217302858e70fa4Paul Duffin Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class; 4970888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (java.lang.reflect.Field f : k.getDeclaredFields()) { 4980888a09821a98ac0680fad765217302858e70fa4Paul Duffin f.setAccessible(true); 4990888a09821a98ac0680fad765217302858e70fa4Paul Duffin Object x = f.get(null); 5000888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (k.isInstance(x)) 5010888a09821a98ac0680fad765217302858e70fa4Paul Duffin return k.cast(x); 5020888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5030888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw new NoSuchFieldError("the Unsafe"); 5040888a09821a98ac0680fad765217302858e70fa4Paul Duffin }}); 5050888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (java.security.PrivilegedActionException e) { 5060888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw new RuntimeException("Could not initialize intrinsics", 5070888a09821a98ac0680fad765217302858e70fa4Paul Duffin e.getCause()); 5080888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5090888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5100888a09821a98ac0680fad765217302858e70fa4Paul Duffin private volatile RunnableExecutorPair head = NULL_PAIR; 5110888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5120888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void add(Runnable runnable, Executor executor) { 5130888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(runnable, "Runnable was null."); 5140888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(executor, "Executor was null."); 5150888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5160888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair newHead = new RunnableExecutorPair(runnable, executor); 5170888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair oldHead; 5180888a09821a98ac0680fad765217302858e70fa4Paul Duffin do { 5190888a09821a98ac0680fad765217302858e70fa4Paul Duffin oldHead = head; 5200888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (oldHead == null) { 5210888a09821a98ac0680fad765217302858e70fa4Paul Duffin // If runnables == null then execute() has been called so we should just execute our 5220888a09821a98ac0680fad765217302858e70fa4Paul Duffin // listener immediately. 5230888a09821a98ac0680fad765217302858e70fa4Paul Duffin newHead.execute(); 5240888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 5250888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5260888a09821a98ac0680fad765217302858e70fa4Paul Duffin // Try to make newHead the new head of the stack at runnables. 5270888a09821a98ac0680fad765217302858e70fa4Paul Duffin newHead.next = oldHead; 5280888a09821a98ac0680fad765217302858e70fa4Paul Duffin } while (!UNSAFE.compareAndSwapObject(this, HEAD_OFFSET, oldHead, newHead)); 5290888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5300888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5310888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void execute() { 5320888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair stack; 5330888a09821a98ac0680fad765217302858e70fa4Paul Duffin do { 5340888a09821a98ac0680fad765217302858e70fa4Paul Duffin stack = head; 5350888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (stack == null) { 5360888a09821a98ac0680fad765217302858e70fa4Paul Duffin // If head == null then execute() has been called so we should just return 5370888a09821a98ac0680fad765217302858e70fa4Paul Duffin return; 5380888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5390888a09821a98ac0680fad765217302858e70fa4Paul Duffin // try to swap null into head. 5400888a09821a98ac0680fad765217302858e70fa4Paul Duffin } while (!UNSAFE.compareAndSwapObject(this, HEAD_OFFSET, stack, null)); 5410888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5420888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair reversedStack = null; 5430888a09821a98ac0680fad765217302858e70fa4Paul Duffin while (stack != NULL_PAIR) { 5440888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair head = stack; 5450888a09821a98ac0680fad765217302858e70fa4Paul Duffin stack = stack.next; 5460888a09821a98ac0680fad765217302858e70fa4Paul Duffin head.next = reversedStack; 5470888a09821a98ac0680fad765217302858e70fa4Paul Duffin reversedStack = head; 5480888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5490888a09821a98ac0680fad765217302858e70fa4Paul Duffin stack = reversedStack; 5500888a09821a98ac0680fad765217302858e70fa4Paul Duffin while (stack != null) { 5510888a09821a98ac0680fad765217302858e70fa4Paul Duffin stack.execute(); 5520888a09821a98ac0680fad765217302858e70fa4Paul Duffin stack = stack.next; 5530888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5540888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5550888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5560888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static class RunnableExecutorPair { 5570888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Runnable runnable; 5580888a09821a98ac0680fad765217302858e70fa4Paul Duffin final Executor executor; 5590888a09821a98ac0680fad765217302858e70fa4Paul Duffin // Volatile because this is written on one thread and read on another with no synchronization. 5600888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Nullable volatile RunnableExecutorPair next; 5610888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5620888a09821a98ac0680fad765217302858e70fa4Paul Duffin RunnableExecutorPair(Runnable runnable, Executor executor) { 5630888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.runnable = runnable; 5640888a09821a98ac0680fad765217302858e70fa4Paul Duffin this.executor = executor; 5650888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5660888a09821a98ac0680fad765217302858e70fa4Paul Duffin 5670888a09821a98ac0680fad765217302858e70fa4Paul Duffin void execute() { 5680888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 5690888a09821a98ac0680fad765217302858e70fa4Paul Duffin executor.execute(runnable); 5700888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (RuntimeException e) { 5710888a09821a98ac0680fad765217302858e70fa4Paul Duffin log.log(Level.SEVERE, "RuntimeException while executing runnable " 5720888a09821a98ac0680fad765217302858e70fa4Paul Duffin + runnable + " with executor " + executor, e); 5730888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5740888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5750888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5760888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 5770888a09821a98ac0680fad765217302858e70fa4Paul Duffin} 578