|
import java.util.List; |
|
import java.util.concurrent.CountDownLatch; |
|
import java.util.concurrent.atomic.LongAdder; |
|
import java.util.stream.Stream; |
|
|
|
import static java.lang.Thread.sleep; |
|
import static java.util.Arrays.asList; |
|
import static java.util.Collections.emptyList; |
|
import static java.util.stream.Collectors.toList; |
|
|
|
public class ButtonRace { |
|
|
|
public static void main(String[] args) throws InterruptedException { |
|
Button ok = new Button("OK", () -> System.out.println("TASK: OK")); |
|
Button cancel = new Button("CANCEL", () -> System.out.println("TASK: CANCEL")); |
|
|
|
// Button ok = new Button("OK"); |
|
// Button cancel = new Button("CANCEL"); |
|
|
|
CountDownLatch start = new CountDownLatch(1); |
|
List<Thread> threads = Stream.of(ok, cancel).map(button -> new Thread(() -> { |
|
try { |
|
start.await(); |
|
while (!Thread.currentThread().isInterrupted()) { |
|
button.click(); |
|
} |
|
} catch (Exception ignored) { |
|
} |
|
})).collect(toList()); |
|
threads.forEach(Thread::start); |
|
start.countDown(); |
|
|
|
sleep(5_000); |
|
threads.forEach(Thread::interrupt); |
|
for (Thread thread : threads) { |
|
thread.join(); |
|
} |
|
|
|
System.out.println(ok); |
|
System.out.println(cancel); |
|
} |
|
|
|
public static class Button { |
|
private final String name; |
|
|
|
private final List<Runnable> tasks; |
|
private final LongAdder clicks = new LongAdder(); |
|
|
|
public Button(String name) { |
|
this.name = name; |
|
this.tasks = emptyList(); |
|
} |
|
|
|
public Button(String name, Runnable... runnable) { |
|
this.name = name; |
|
this.tasks = asList(runnable); |
|
} |
|
|
|
public void click() { |
|
clicks.increment(); |
|
synchronized (tasks) { |
|
//System.out.println("Clicking(" + this + ")"); |
|
doingSomeWork(); |
|
tasks.forEach(Runnable::run); |
|
//System.out.println("Clicked(" + this + ")"); |
|
} |
|
} |
|
|
|
// [...] |
|
|
|
@Override |
|
public String toString() { |
|
return name + ": " + clicks + " clicks"; |
|
} |
|
|
|
private void doingSomeWork() { |
|
try { |
|
sleep(100); |
|
} catch (InterruptedException e) { |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
} |
|
|
|
} |