Skip to content

Instantly share code, notes, and snippets.

@jakelandis
Last active January 16, 2020 20:13
Show Gist options
  • Save jakelandis/10519b9596888d8eb548d9fab28e4661 to your computer and use it in GitHub Desktop.
Save jakelandis/10519b9596888d8eb548d9fab28e4661 to your computer and use it in GitHub Desktop.
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
class Scratch {
//for loop with sync or async actions processed in order with a post work step
public static void main(String[] args) throws InterruptedException {
String[] letters = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
ExecutorService executorService = Executors.newFixedThreadPool(10);
System.out.println("*************** Baseline ************");
baseline(letters);
System.out.println("*************** Sync:1 ************");
option1(letters, new SyncProcessor(), 0, Thread.currentThread());
Thread.sleep(1000);
System.out.println("*************** Async:1 ************");
option1(letters, new AsyncProcessor(executorService), 0, Thread.currentThread());
Thread.sleep(1000);
System.out.println("*************** Sync:2 ************");
option2(letters, new SyncProcessor(), 0, Thread.currentThread());
Thread.sleep(1000);
System.out.println("*************** Async:2 ************");
option2(letters, new AsyncProcessor(executorService), 0, Thread.currentThread());
Thread.sleep(1000);
System.out.println("*************** Sync:3 ************");
option3(letters, new SyncProcessor(), 0, Thread.currentThread());
Thread.sleep(1000);
System.out.println("*************** Async:3 ************");
option3(letters, new AsyncProcessor(executorService), 0, Thread.currentThread());
Thread.sleep(1000);
executorService.shutdown();
}
//properly ordered
public static void baseline(String[] letters) {
Arrays.stream(letters).forEach(System.out::println);
System.out.println("end");
}
//sync - properly ordered, but deep stack
//async - properly ordered
public static void option1(String[] letters, Processor processor, int i, Thread mainThread) {
if (i == letters.length) {
System.out.println("end");
return;
}
processor.process(letters[i], (l) -> {
System.out.println(l + " [" + mainThread.getStackTrace().length + "]");
option1(letters, processor, i + 1, mainThread);
});
}
//sync - properly ordered, no deep stack, but requires forking
//async - properly ordered
public static void option2(String[] letters, Processor processor, int i, Thread mainThread) {
if (i == letters.length) {
System.out.println("end");
return;
}
final Thread thread = Thread.currentThread();
processor.process(letters[i], (l) -> {
System.out.println(l + " [" + mainThread.getStackTrace().length + "]");
if (thread == Thread.currentThread()) {
//synchronous, so need to fork the recursive call to avoid deep stack
new Thread(() -> option2(letters, processor, i + 1, mainThread)).start();
} else {
option2(letters, processor, i + 1, mainThread);
}
});
}
//credit: https://github.com/probakowski
//sync - properly ordered, no deep stack, no forking
//async - properly ordered
public static void option3(String[] letters, Processor processor, int i, Thread mainThread) {
for (; i < letters.length; i++) {
AtomicBoolean shouldContinueHere = new AtomicBoolean();
int nextIndex = i + 1;
processor.process(letters[i], (l) -> {
System.out.println(l + " [" + mainThread.getStackTrace().length + "]");
if (shouldContinueHere.getAndSet(true)) {
option3(letters, processor, nextIndex, mainThread);
}
});
if (shouldContinueHere.getAndSet(true) == false) {
return;
}
}
if (i == letters.length) {
System.out.println("end");
}
}
interface Processor {
void process(String letter, Consumer<String> handler);
}
static class SyncProcessor implements Processor {
public void process(String letter, Consumer<String> handler) {
handler.accept(letter);
}
}
static class AsyncProcessor implements Processor {
final ExecutorService executorService;
AsyncProcessor(ExecutorService executorService) {
this.executorService = executorService;
}
public void process(String letter, Consumer<String> handler) {
executorService.submit(() -> handler.accept(letter));
}
}
}
/**
output:
*************** Baseline ************
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
end
*************** Sync:1 ************
a [5]
b [8]
c [11]
d [14]
e [17]
f [20]
g [23]
h [26]
i [29]
j [32]
k [35]
l [38]
m [41]
n [44]
o [47]
p [50]
q [53]
r [56]
s [59]
t [62]
u [65]
v [68]
w [71]
x [74]
y [77]
z [80]
end
*************** Async:1 ************
a [2]
b [2]
c [2]
d [2]
e [2]
f [2]
g [2]
h [2]
i [2]
j [2]
k [2]
l [2]
m [2]
n [2]
o [2]
p [2]
q [2]
r [2]
s [2]
t [2]
u [2]
v [2]
w [2]
x [2]
y [2]
z [2]
end
*************** Sync:2 ************
a [5]
b [2]
c [2]
d [2]
e [2]
f [2]
g [2]
h [2]
i [2]
j [2]
k [2]
l [2]
m [2]
n [2]
o [2]
p [2]
q [2]
r [2]
s [2]
t [2]
u [2]
v [2]
w [2]
x [2]
y [2]
z [2]
end
*************** Async:2 ************
a [2]
b [2]
c [2]
d [2]
e [2]
f [2]
g [2]
h [2]
i [2]
j [2]
k [2]
l [2]
m [2]
n [2]
o [2]
p [2]
q [2]
r [2]
s [2]
t [2]
u [2]
v [2]
w [2]
x [2]
y [2]
z [2]
end
*************** Sync:3 ************
a [5]
b [5]
c [5]
d [5]
e [5]
f [5]
g [5]
h [5]
i [5]
j [5]
k [5]
l [5]
m [5]
n [5]
o [5]
p [5]
q [5]
r [5]
s [5]
t [5]
u [5]
v [5]
w [5]
x [5]
y [5]
z [5]
end
*************** Async:3 ************
a [2]
b [2]
c [2]
d [2]
e [2]
f [2]
g [2]
h [2]
i [2]
j [2]
k [2]
l [2]
m [2]
n [2]
o [2]
p [2]
q [2]
r [2]
s [2]
t [2]
u [2]
v [2]
w [2]
x [2]
y [2]
z [2]
end
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment