Funkcjonalny sposób wdrożenia licznika bezpiecznego dla wątków

Jestem stosunkowo nowy w Scali i programowaniu funkcjonalnym i podoba mi się pomysł, że używając niezmiennych obiektów mogę uniknąć wielu pułapek bezpieczeństwa wątków. Jedna rzecz wciąż mnie prześladuje i jest to klasyczny przykład używany do nauczania bezpieczeństwa nici - wspólnego licznika.

Zastanawiałem się, czy możliwe byłoby zaimplementowanie licznika bezpiecznego dla wątków (w tym przykładzie licznika żądań), użycie niezmiennych obiektów i pojęć funkcjonalnych oraz całkowite uniknięcie synchronizacji.

Więc dla odniesienia tutaj są najpierw klasyczne, zmienne wersje licznika (przepraszam za zmienną członka publicznego, tylko dla zwięzłości przykładów)

Mutable, Non thread safe version:

public class Servlet extends HttpServlet {

  public int requestCount = 0; 

  @Override
  public void service(ServletRequest req, ServletResponse res) throws ... {
    requestCount++; //thread unsafe
    super.service(req, res);  
  }
}

Zmutowana, klasyczna bezpieczna wersja nici: (a przynajmniej mam nadzieję ...)

public class Servlet extends HttpServlet {

  public volatile int requestCount = 0;

  @Override
  public void service(ServletRequest req, ServletResponse res) throws ... {
    synchronized (this) {
      requestCount++;
    }
    super.service(req, res);  
  }
}

Zastanawiałem się, czy istnieje sposób wykorzystania niezmiennych obiektów i zmiennych zmiennych, aby osiągnąć bezpieczeństwo wątku bez synchronizacji.

Oto moja naiwna próba. Chodzi o to, aby mieć niezmienny obiekt dla licznika i po prostu zastąpić odniesienie do niego, używając zmiennej lotnej. Czuje się podejrzanie, ale warto spróbować.

Uchwyt:

public class Incrementer {
  private final int value;
  public Incrementer(final int oldValue) {
    this.value = oldValue + 1;
  }

  public Incrementer() {
    this.value = 0;
  }

  public int getValue() {
    return value;
  }
}

Zmodyfikowany serwlet:

public class Servlet extends HttpServlet {

  public volatile Incrementer incrementer = new Incrementer();

  @Override
  public void service(ServletRequest req, ServletResponse res) throws ... {
    incrementer = new Incrementer(incrementer.getValue());
    super.service(req, res);
  }
}

Mam silne przeczucie, że to również nie jest bezpieczne dla wątków, ponieważ czytam z inkrementatora i może uzyskać nieaktualną wartość (np. Jeśli odwołanie zostało już zastąpione innym wątkiem). W przypadku, gdy rzeczywiście nie jest bezpieczny dla wątków, zastanawiam się, czy w ogóle istnieje jakikolwiek „funkcjonalny” sposób na obsłużenie takiego scenariusza bez blokowania / synchronizacji.

Więc moje pytania są

Czy ten wątek jest bezpieczny przez przypadek?Jeśli tak, to dlaczego?Jeśli nie, czy istnieje jakikolwiek sposób na wdrożenie takiego licznika bez synchronizacji?

Chociaż powyższy przykładowy kod znajduje się w Javie, odpowiedzi w Scali są oczywiście mile widziane

questionAnswers(2)

yourAnswerToTheQuestion