blob: 8fe2cc2e41989f5a4f94ee8b1769d33cc9333906 [file] [log] [blame]
Jordan Halterman9bdc24f2017-04-19 23:45:12 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onlab.util;
17
18import java.util.LinkedList;
19import java.util.concurrent.Executor;
20
21/**
Jordan Halterman046faeb2017-05-01 15:10:13 -070022 * Executor that executes tasks in order on a shared thread pool.
Jordan Halterman9bdc24f2017-04-19 23:45:12 -070023 * <p>
Jordan Halterman046faeb2017-05-01 15:10:13 -070024 * The ordered executor behaves semantically like a single-threaded executor, but multiplexes tasks on a shared thread
25 * pool, ensuring blocked threads in the shared thread pool don't block individual ordered executors.
Jordan Halterman9bdc24f2017-04-19 23:45:12 -070026 */
Jordan Halterman046faeb2017-05-01 15:10:13 -070027public class OrderedExecutor implements Executor {
Jordan Halterman9bdc24f2017-04-19 23:45:12 -070028 private final Executor parent;
29 private final LinkedList<Runnable> tasks = new LinkedList<>();
30 private boolean running;
31
Jordan Halterman046faeb2017-05-01 15:10:13 -070032 public OrderedExecutor(Executor parent) {
Jordan Halterman9bdc24f2017-04-19 23:45:12 -070033 this.parent = parent;
34 }
35
36 private void run() {
37 for (;;) {
38 final Runnable task;
39 synchronized (tasks) {
40 task = tasks.poll();
41 if (task == null) {
42 running = false;
43 return;
44 }
45 }
46 task.run();
47 }
48 }
49
50 @Override
51 public void execute(Runnable command) {
52 synchronized (tasks) {
53 tasks.add(command);
54 if (!running) {
55 running = true;
56 parent.execute(this::run);
57 }
58 }
59 }
60}