Rob Bosman 3-12-2019
class FetchJokeService {
private static final Logger LOG = LoggerFactory.getLogger(FetchJokeServiceJava.class);
private static final String API_URL
= "http://api.icndb.com/jokes/random?limitTo=[explicit,nerdy]"; // Chuck Norris jokes
static String fetchJoke() {
LOG.debug("fetch joke");
try {
final HttpURLConnection connection = (HttpURLConnection) new URL(API_URL).openConnection();
try {
try (final BufferedReader reader
= new BufferedReader(new InputStreamReader(connection.getInputStream(), UTF_8))) {
return reader.lines().collect(joining());
} catch (IOException e) {
throw new RuntimeException("Error reading from InputStream", e);
}
} finally {
connection.disconnect();
LOG.debug("fetched joke");
}
} catch (MalformedURLException e) {
throw new RuntimeException("Error in URL " + API_URL, e);
} catch (IOException e) {
throw new RuntimeException("Error connecting to " + API_URL, e);
}
}
}Runnable
ThreadPool
ThreadLocal
InterruptedException
Hashtable
Semaphore
synchronized
volatile
ConcurrentHashMap
fork / join
Future
private fun findTheAnswer(): Int {
log.debug("pondering...")
Thread.sleep(1_000)
return 42
}
fun backToTheFuture() {
val executor = Executors.newFixedThreadPool(2)
val future = executor.submit(::findTheAnswer)
log.debug("are you done? - ${future.isDone}")
// do other stuff
val answer = future.get() // blocking wait
log.debug("ah, the answer is $answer")
executor.shutdown()
}fun backToTheCompletableFuture() {
val provideAnswerCF = CompletableFuture
.supplyAsync {
log.debug("determine required processing time")
1500L
}
.thenApply { delayMillis ->
log.debug("pondering...")
Thread.sleep(delayMillis)
42
}
.thenApply { answer ->
log.debug("got it!")
answer
}
log.debug("do you know the answer? - ${provideAnswerCF.isDone}")
log.debug("ah, the answer is ${provideAnswerCF.get()}") // blocking wait
}fun backToTheCompletableFuture() {
val provideAnswerCF = CompletableFuture
.supplyAsync {
log.debug("determine required processing time")
1500L
}
.thenApply { delayMillis ->
log.debug("pondering...")
Thread.sleep(delayMillis)
42
}
.thenApply { answer ->
log.debug("got it!")
answer
}
log.debug("do you know the answer? - ${provideAnswerCF.isDone}")
log.debug("ah, the answer is ${provideAnswerCF.get()}") // blocking wait
}fun backToTheCompletableFuture() {
val provideAnswerCF = CompletableFuture
.supplyAsync {
log.debug("determine required processing time")
1500L
}
.thenApply { delayMillis ->
log.debug("pondering...")
Thread.sleep(delayMillis)
42
}
.thenApply { answer ->
log.debug("got it!")
answer
}
log.debug("do you know the answer? - ${provideAnswerCF.isDone}")
log.debug("ah, the answer is ${provideAnswerCF.get()}") // blocking wait
}is a Functor
flatten (flatMap)
A monad is just a monoid in the category of endofunctors, what's the problem?
fun backToTheCompletableFuture() {
val provideAnswerCF = CompletableFuture
.supplyAsync {
log.debug("determine required processing time")
1500L
}
.thenApply { delayMillis ->
log.debug("pondering...")
Thread.sleep(delayMillis)
42
}
.thenApply { answer ->
log.debug("got it!")
answer
}
log.debug("do you know the answer? - ${provideAnswerCF.isDone}")
log.debug("ah, the answer is ${provideAnswerCF.get()}") // blocking wait
}
A morphism from a source category to a target category which maps objects to objects and arrows to arrows, in such a way as to preserve domains and codomains (of the arrows) as well as composition and identities.
Rabbi Jehoeda Löw
A morphism from a source category to a target category which maps objects to objects and arrows to arrows, in such a way as to preserve domains and codomains (of the arrows) as well as composition and identities.
fun run() {
log.debug("here we go")
val processControl = Semaphore(0)
val jokeJsonO = Observable
.create<String> { emitter -> emitter.onNext(fetchJoke()) }
.subscribeOn(Schedulers.io())
Observable
.create<MongoClient> { emitter -> emitter.onNext(getMongoClient()) }
.subscribeOn(Schedulers.io())
.zipWith(jokeJsonO,
BiFunction { mongoClient: MongoClient, jokeJson: String ->
val joke = convertAndStore(jokeJson, mongoClient)
mongoClient.close()
log.debug("closed MongoDB client")
joke
})
.subscribe { joke ->
log.info("'$joke'")
processControl.release()
}
log.debug("wait until all is done")
processControl.tryAcquire(3_000, MILLISECONDS)
log.debug("there you are!")
}goto(label);throw new Exception();fun backToResilience() {
log.debug("here we go")
val processControl = Semaphore(0)
Single
.create<String> { emitter -> emitter.onSuccess(fetchJokeFlaky()) }
.timeout(200, MILLISECONDS)
.subscribeOn(Schedulers.io())
.doOnSuccess { jokeJson ->
if (!jokeJson.contains("success"))
throw Throwable("invalid data: $jokeJson")
}
.doOnError { t -> log.warn("error detected: '${t.message}'", t) }
.retry(3)
.onErrorResumeNext(Single.just("fallback jokeJson"))
.doFinally { processControl.release() }
.subscribe(
{ jokeJson -> log.info("'$jokeJson'") },
{ t -> log.error("an ERROR occurred", t) })
log.debug("wait a second...")
processControl.tryAcquire(1_000, MILLISECONDS)
log.debug("there you are!")
}fun backToResilience() {
log.debug("here we go")
val processControl = Semaphore(0)
Single
.create<String> { emitter -> emitter.onSuccess(fetchJokeFlaky()) }
.timeout( 200, MILLISECONDS)
.subscribeOn( Schedulers.io())
.doOnSuccess { jokeJson ->
if (!jokeJson.contains("success"))
throw Throwable("invalid data: $jokeJson")
}
.doOnError { t -> log.warn("error detected: '${t.message}'", t) }
.retry( 3)
.onErrorResumeNext( Single.just("fallback jokeJson"))
.doFinally { processControl.release() }
.subscribe(
{ jokeJson -> log.info("'$jokeJson'") },
{ t -> log.error("an ERROR occurred", t) })
log.debug("wait a second...")
processControl.tryAcquire(1_000, MILLISECONDS)
log.debug("there you are!")
}fun backToResilience() {
log.debug("here we go")
val processControl = Semaphore(0)
Single
.create<String> { emitter -> emitter.onSuccess(fetchJokeFlaky()) }
.timeout(200, MILLISECONDS)
.subscribeOn(Schedulers.io())
.doOnSuccess { jokeJson ->
if (!jokeJson.contains("success"))
throw Throwable("invalid data: $jokeJson")
}
.doOnError { t -> log.warn("error detected: '${t.message}'", t) }
.retry(3)
.onErrorResumeNext(Single.just("fallback jokeJson"))
.doFinally { processControl.release() }
.subscribe(
{ jokeJson -> log.info("'$jokeJson'") },
{ t -> log.error("an ERROR occurred", t) })
log.debug("wait a second...")
processControl.tryAcquire(1_000, MILLISECONDS)
log.debug("there you are!")
}
github.com/
RobBosman/
BeReactive
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.concurrent.thread
internal object ParallelProcessingTest {
@Test
fun withThreads() {
val startNano = System.nanoTime()
val endNano = AtomicLong()
val count = AtomicInteger()
IntStream.range(0, NUM_PARALLEL_PROCESSES)
.forEach {
thread(start = true) {
log.debug("performing task in thread")
Thread.sleep(1_000)
if (count.incrementAndGet() == NUM_PARALLEL_PROCESSES)
endNano.set(System.nanoTime())
}
}
while (endNano.get() == 0L) Thread.yield()
log.debug("${count.get()} Thread-tasks took ${endNano.get().minus(startNano) / 1_000_000} ms")
}
}github.com/
RobBosman/
BeReactive