Po przeczytaniu sąsiedniego wątku, napisałem sobie prostą aplikacyjkę w webfluxie z licznikiem, aby sprawdzić kolejność wykonywania wątków.
Counter.java:
public class Counter {
public final long counter;
public Counter(long counter) {
this.counter = counter;
}
public Counter updateCounter() {
return new Counter(this.counter + 1);
}
}
CounterController.java
@Configuration
public class CounterController {
private final CounterService counterService;
public CounterController() {
this.counterService = new CounterService(new Counter(0));
}
@Bean
RouterFunction<ServerResponse> counterRoutes() {
return nest(path("/api"),
route(GET("/counter"), counterValue())
.andRoute(PATCH("/counter"), increaseCounterValue()));
}
private HandlerFunction<ServerResponse> counterValue() {
return request -> {
final long counterValue = this.counterService.getCounterValue();
return ServerResponse.ok().body(fromObject(counterValue));
};
}
private HandlerFunction<ServerResponse> increaseCounterValue() {
return request -> {
final long counterValue = this.counterService.increaseCounterValue();
return ServerResponse.ok().body(fromObject(counterValue));
};
}
}
CounterService.java
public class CounterService {
private Counter counter;
public CounterService(Counter counter) {
this.counter = counter;
}
public long getCounterValue() {
System.out.println("pobieram countera simple: " + this.counter.counter);
return this.counter.counter;
}
public long increaseCounterValue() {
this.counter = this.counter.updateCounter();
System.out.println("zaktualizowalem countera simple: " + this.counter.counter);
return this.counter.counter;
}
}
Następnie puściłem JMeterem 100 wątków x 100 requestów. W konsoli ostatni wpis:
zaktualizowalem countera simple: 8749
Zmieniając na public synchronized long increaseCounterValue() {...}
w CounterService.java, ostatni wpis w konosli:
zaktualizowalem countera synchronized: 10000
Zmieniając long
na AtomicLong
w Counter.java (i oczywiście bez synchronized w serwisie)
zaktualizowalem countera atomic: 10000
Robiąc tak jak w pierwszym przykładzie, tylko definiując counter w CounterService.java private volatile Counter counter;
zaktualizowalem countera volatile: 8873
Pytanie
W jaki sposób poprawnie użyć volatile
?
W tym temacie Dostarczanie danych przez REST i ich aktualizacja @jarekr000000 mnie zbił z tropu stwierdzeniem, że synchronized
jest niewystarczające. W powyższym przykładzie wygląda OK, a nie bardzo wiem czym się różni od kodu @eL ?
PS. Bez sensu podawać czasy benchmarków dla wszystkich 4 przypadków (bez warmupów, kupe innych rzeczy w tle odpalonych itp), ale jak kogoś bardzo to interesuje to wszystkie wykonywały się niemal identycznie na poziomie:
GET (sr, min, max): 16, 0, 32 ms
i PATCH(sr, min, max): 1, 0, 9 ms