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