Questa classe è sicura per i thread?

0

Ho una classe di entità

    package org.demo.stack;

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;

    @Entity
    public class ValueHolder{
        @Id
        private Long id;

        @Column
        private Long value;

        /* getters and setters... */
    }

un relativo repository JPA di primavera

    package org.demo.stack;

    import org.springframework.data.jpa.repository.JpaRepository;

    public interface ValueHolderRepository extends JpaRepository<ValueHolder, Long>
    {
    }

e una classe che funge da accumulatore di alcuni tipi di valori, utilizzando il repository (Si noti che questa è una versione semplificata di un vero programma)

    package org.demo.stack;

    import java.util.List;

    public class ValueAccumulator{
        private ValueHolderRepository repository;
        private Long accumulator;

        public ValueAccumulator(ValueHolderRepository repository){
            this.repository = repository;
            accumulator = 0L;
        }

        public Long sumOverResults(){
            accumulator = 0L;

            List<ValueHolder> holders = repository.findAll();
            for(ValueHolder holder : holders){
                accumulator = accumulator + holder.getValue();
            }
            return accumulator;
        }
    }

ValueAccumulator non è chiaramente thread-safe. Se condivido la stessa istanza su diversi thread e sumOverResults è chiamato contemporaneamente, il variabile d'istanza accumulator avrà un valore non prevedibile.

Ho anche un adattatore che assomiglia a ConcurrentValueAccumulator :

    package org.demo.stack;

    public class ConcurrentValueAccumulator{
        private ValueHolderRepository repository;

        public Long sumOverResults(){
            ValueAccumulator oneShotAccumulator = new ValueAccumulator(repository);
            return oneShotAccumulator.sumOverResults();
        }
    }

Ora ogni chiamata a sumOverResults utilizza la propria istanza di ValueAccumulator , quindi nessun dato sono condivisi tra thread. Partendo dal presupposto che nessun ValueEntity s viene inserito o aggiornato durante il processo, posso essere sicuro al 100% che ConcurrentValueAccumulator sia thread-safe?

    
posta Evil Toad 26.08.2016 - 11:28
fonte

1 risposta

2

Come per il codice fornito qui, hai ragione, se guardiamo la classe ValueAccumulator separatamente, quindi sicuramente non è un thread-safe (per la ragione ovvia che hai fornito nella domanda).

Ora Se stai usando la classe ValueAccumulator tramite ConcurrentValueAccumulator, allora ho le seguenti osservazioni:

  1. Nel metodo sumOverResults() , ogni volta che viene creata la nuova istanza di ValueAccumulator , quindi ogni thread avrà la propria istanza, nessuna istanza di ValueAccumulator è condivisa tra i thread, quindi non c'è alcun punto di corruzione dei dati in quanto i thread stanno lavorando sui propri oggetti di ValueAccumulator , quindi non c'è bisogno di alcuna sincronizzazione qui.

  2. Nella classe ConcurrentValueAccumulator,

       private ValueHolderRepository repository;
    

    Il repository è comune in tutte le istanze di ValueAccumulator , quindi a questo punto possiamo pensare ad alcuni thread di sicurezza perché abbiamo qualcosa che è condiviso tra diversi thread (repository nel nostro caso). Ma nel codice fornito qui, stiamo solo leggendo il repository e

there is no create/update/write operation on repository instance

, quindi ancora non c'è bisogno di alcuna sincronizzazione qui.

Quindi, il codice è thread-safe (a condizione che stiamo facendo qualsiasi operazione di creazione / scrittura / aggiornamento su qualsiasi dato condiviso).

    
risposta data 26.08.2016 - 14:09
fonte

Leggi altre domande sui tag