Zoeken…


Invoering

Een gelijktijdige verzameling is een [verzameling] [1] die toegang mogelijk maakt met meer dan één thread tegelijkertijd. Verschillende threads kunnen doorgaans de inhoud van de verzameling doorlopen en elementen toevoegen of verwijderen. De verzameling is ervoor verantwoordelijk dat de verzameling niet corrupt wordt. [1]: http://stackoverflow.com/documentation/java/90/collections#t=201612221936497298484

Draadveilige collecties

Standaard zijn de verschillende Collectietypen niet thread-safe.

Het is echter vrij eenvoudig om een verzameling thread-safe te maken.

List<String> threadSafeList = Collections.synchronizedList(new ArrayList<String>());
Set<String> threadSafeSet = Collections.synchronizedSet(new HashSet<String>());
Map<String, String> threadSafeMap = Collections.synchronizedMap(new HashMap<String, String>());

Wanneer u een thread-safe collectie maakt, mag u deze nooit openen via de originele collectie, alleen via de thread-safe wrapper.

Java SE 5

Vanaf Java 5 heeft java.util.collections verschillende nieuwe thread-safe collecties die niet de verschillende Collections.synchronized methoden nodig hebben.

List<String> threadSafeList = new CopyOnWriteArrayList<String>();
Set<String> threadSafeSet = new ConcurrentHashSet<String>();
Map<String, String> threadSafeMap = new ConcurrentHashMap<String, String>();

Gelijktijdige collecties

Gelijktijdige collecties zijn een generalisatie van thread-safe collecties, die een breder gebruik in een gelijktijdige omgeving mogelijk maken.

Hoewel thread-safe collecties veilig element toevoegen of verwijderen uit meerdere threads, hebben ze niet noodzakelijkerwijs veilige iteratie in dezelfde context (de ene is mogelijk niet in staat om de collectie in de ene thread veilig te doorlopen, terwijl een andere deze wijzigt door / toe te voegen / elementen verwijderen).

Hier worden gelijktijdige collecties gebruikt.

Omdat iteratie vaak de addAll is van verschillende addAll in collecties, zoals addAll , removeAll , of ook het kopiëren van collecties (via een constructor of op een andere manier), sorteren, ... de use case voor gelijktijdige collecties is eigenlijk vrij groot.

De Java SE 5 java.util.concurrent.CopyOnWriteArrayList is bijvoorbeeld een thread-veilige en gelijktijdige implementatie van Lis , de javadoc staat:

De iteratiemethode in "snapshot" -stijl gebruikt een verwijzing naar de status van de array op het moment dat de iterator is gemaakt. Deze array verandert nooit tijdens de levensduur van de iterator, dus interferentie is onmogelijk en de iterator zal gegarandeerd geen ConcurrentModificationException gooien.

Daarom is de volgende code veilig:

public class ThreadSafeAndConcurrent {

public static final List<Integer> LIST = new CopyOnWriteArrayList<>();

public static void main(String[] args) throws InterruptedException {
    Thread modifier = new Thread(new ModifierRunnable());
    Thread iterator = new Thread(new IteratorRunnable());
    modifier.start();
    iterator.start();
    modifier.join();
    iterator.join();
}

public static final class ModifierRunnable implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 50000; i++) {
                LIST.add(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static final class IteratorRunnable implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10000; i++) {
                long total = 0;
                for(Integer inList : LIST) {
                    total += inList;
                }
                System.out.println(total);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
}

Een andere gelijktijdige verzameling met betrekking tot iteratie is ConcurrentLinkedQueue , waarin staat:

Iterators zijn zwak consistent, terugkerende elementen die de status van de wachtrij weerspiegelen op een bepaald punt op of sinds de oprichting van de iterator. Ze gooien java.util.ConcurrentModificationException niet en kunnen gelijktijdig met andere bewerkingen doorgaan. Elementen in de wachtrij sinds het maken van de iterator worden precies één keer geretourneerd.

Men zou de javadocs moeten controleren om te zien of een verzameling gelijktijdig is of niet. De kenmerken van de iterator die worden geretourneerd door de methode iterator() ("fail fast", "zwak consistent", ...) is het belangrijkste kenmerk waarnaar moet worden gezocht.

Voer veilige maar niet-gelijktijdige voorbeelden in

In bovenstaande code wordt de LIST aangifte gewijzigd in

public static final List<Integer> LIST = Collections.synchronizedList(new ArrayList<>());

Kan (en statistisch gezien op de meeste moderne, multi-CPU / core-architecturen) leiden tot uitzonderingen.

Gesynchroniseerde collecties uit de Collections zijn veilig voor het toevoegen / verwijderen van elementen, maar niet voor iteratie (tenzij de onderliggende collectie dat al wordt doorgegeven).

Invoegen in ConcurrentHashMap

public class InsertIntoConcurrentHashMap
{

    public static void main(String[] args)
    {
        ConcurrentHashMap<Integer, SomeObject> concurrentHashMap = new ConcurrentHashMap<>();

        SomeObject value = new SomeObject();
        Integer key = 1;

        SomeObject previousValue = concurrentHashMap.putIfAbsent(1, value);
        if (previousValue != null)
        {
            //Then some other value was mapped to key = 1. 'value' that was passed to
            //putIfAbsent method is NOT inserted, hence, any other thread which calls
            //concurrentHashMap.get(1) would NOT receive a reference to the 'value'  
            //that your thread attempted to insert. Decide how you wish to handle             
            //this situation.
        }

       else
       {
            //'value' reference is mapped to key = 1.
       }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow