blob: 9e54ac232fd7a1aa7080c295600d8c04eae81f66 [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/**
22 * Executor that executes tasks in serial on a shared thread pool.
23 * <p>
24 * The serial 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 serial executors.
26 */
27public class SerialExecutor implements Executor {
28 private final Executor parent;
29 private final LinkedList<Runnable> tasks = new LinkedList<>();
30 private boolean running;
31
32 public SerialExecutor(Executor parent) {
33 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}