package com.packt.tfesenko.multithreading.section3; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.Flow.Subscription; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.SubmissionPublisher; import java.util.concurrent.TimeUnit; public class Lesson2 { public static void main(String[] args) { SubmissionPublisher<WeatherForecast> weatherForecastPublisher = new WeatherForecastPublisher(); Subscriber<WeatherForecast> twitterSubscriber = new Flow.Subscriber<WeatherForecast>() { private Flow.Subscription subscription; private final String name = "Twitter Subscriber"; @Override public void onSubscribe(Subscription subscription) { System.out.println(name + " subscribed!"); this.subscription = subscription; subscription.request(1); } @Override public void onNext(WeatherForecast weatherForecast) { System.out.println(Thread.currentThread().getName() + " > Twitting: " + weatherForecast); // You can alternatively use subscription.request(Long.MAX_VALUE) in onSubscribe() subscription.request(1); } @Override public void onError(Throwable throwable) { System.err.println(name + " got an error: " + throwable.getMessage()); } @Override public void onComplete() { System.out.println(name + " completed."); } }; weatherForecastPublisher.subscribe(twitterSubscriber); weatherForecastPublisher.subscribe(new Flow.Subscriber<WeatherForecast>() { private Flow.Subscription subscription; private final String name = "Database Subscriber"; @Override public void onSubscribe(Subscription subscription) { System.out.println(name + " subscribed!"); this.subscription = subscription; subscription.request(1); } @Override public void onNext(WeatherForecast weatherForecast) { System.out.println(Thread.currentThread().getName() + " > Saving to DB: " + weatherForecast); try { TimeUnit.MILLISECONDS.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } subscription.request(1); } @Override public void onError(Throwable throwable) { } @Override public void onComplete() { } }); // close the publisher and associated resources after 10 seconds try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } weatherForecastPublisher.close(); } /** * Modification of the example from JavaDoc for * java.util.concurrent.SubmissionPublisher<T> */ public static class WeatherForecastPublisher extends SubmissionPublisher<WeatherForecast> { final ScheduledFuture<?> periodicTask; final ScheduledExecutorService scheduler; WeatherForecastPublisher() { super(Executors.newFixedThreadPool(2), Flow.defaultBufferSize()); scheduler = new ScheduledThreadPoolExecutor(1); periodicTask = scheduler.scheduleAtFixedRate( // // runs submit() () -> submit(WeatherForecast.nextRandomWeatherForecast()), // 500, 500, TimeUnit.MILLISECONDS); } public void close() { periodicTask.cancel(false); scheduler.shutdown(); super.close(); } } /** * Weather Forecast in United States customary units */ public static class WeatherForecast { private final int temperatureInF; private final int windSpeedInMPH; private final String weatherCondition; private static final Random random = new Random(); private static final String[] allWeatherConditions = new String[] { "☁️", "☀️", "⛅", "🌧", "⛈️" }; public static WeatherForecast nextRandomWeatherForecast() { String weatherCondition = allWeatherConditions[random.nextInt(allWeatherConditions.length)]; int temperatureInF = random.nextInt(95); int windSpeedInMPH = 5 + random.nextInt(30); return new WeatherForecast(temperatureInF, windSpeedInMPH, weatherCondition); } public WeatherForecast(int temperatureInF, int windSpeedInMPH, String weatherCondition) { super(); this.temperatureInF = temperatureInF; this.windSpeedInMPH = windSpeedInMPH; this.weatherCondition = weatherCondition; } @Override public String toString() { return weatherCondition + " " + temperatureInF + "°F wind: " + windSpeedInMPH + "mph"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + temperatureInF; result = prime * result + ((weatherCondition == null) ? 0 : weatherCondition.hashCode()); result = prime * result + windSpeedInMPH; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; WeatherForecast other = (WeatherForecast) obj; if (temperatureInF != other.temperatureInF) return false; if (weatherCondition == null) { if (other.weatherCondition != null) return false; } else if (!weatherCondition.equals(other.weatherCondition)) return false; if (windSpeedInMPH != other.windSpeedInMPH) return false; return true; } } }