Mam ArrayList, którego chcę użyć do przechowywania obiektów RaceCar, które rozszerzają klasę Thread, gdy tylko zostaną zakończone. Klasa o nazwie Race obsługuje tę ArrayList przy użyciu metody wywołania zwrotnego, którą obiekt RaceCar wywołuje po zakończeniu wykonywania. Metoda wywołania zwrotnego addFinisher (RaceCar finisher) dodaje obiekt RaceCar do ArrayList. Ma to na celu zapewnienie kolejności, w jakiej wątki kończą wykonywanie.
Wiem, że ArrayList nie jest zsynchronizowany, a zatem nie jest bezpieczny dla wątków. Próbowałem użyć metody Collections.synchronizedCollection (c Collection), przekazując nową ArrayList i przypisując zwróconą Collection do ArrayList. Jednak to daje mi błąd kompilatora:
Race.java:41: incompatible types
found : java.util.Collection
required: java.util.ArrayList
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));
Oto odpowiedni kod:
public class Race implements RaceListener {
private Thread[] racers;
private ArrayList finishingOrder;
//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));
//Fill array with RaceCar objects
for(int i=0; i<numberOfRaceCars; i++) {
racers[i] = new RaceCar(laps, inputs[i]);
//Add this as a RaceListener to each RaceCar
((RaceCar) racers[i]).addRaceListener(this);
}
//Implement the one method in the RaceListener interface
public void addFinisher(RaceCar finisher) {
finishingOrder.add(finisher);
}
Muszę wiedzieć, czy stosuję poprawne podejście, a jeśli nie, czego należy użyć, aby mój kod był bezpieczny dla wątków? Dzięki za pomoc!
List
interfejs nie jest na tyle kompletny, aby był bardzo przydatny w wielowątkowości.)Collections.synchronizedList()
tego mielibyśmy PRAWDZIWE warunki wyścigu tutaj: POdpowiedzi:
Użyj
Collections.synchronizedList()
.Dawny:
Collections.synchronizedList(new ArrayList<YourClassNameHere>())
źródło
Zmiana
private ArrayList finishingOrder; //Make an ArrayList to hold RaceCar objects to determine winners finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars)
do
private List finishingOrder; //Make an ArrayList to hold RaceCar objects to determine winners finishingOrder = Collections.synchronizedList(new ArrayList(numberOfRaceCars)
Lista jest typem nadrzędnym ArrayList, więc musisz to określić.
W przeciwnym razie to, co robisz, wydaje się w porządku. Inną opcją jest użycie Vector, który jest zsynchronizowany, ale prawdopodobnie tak bym zrobił.
źródło
List
prawdopodobnie byłby bardziej przydatny. LubList<RaceCar>
.//Print out winner System.out.println("The Winner is " + ((RaceCar) finishingOrder.get(0)).toString() + "!");
Mówi, że metoda get (0) nie została znaleziona. Myśli?CopyOnWriteArrayList
Użyj
CopyOnWriteArrayList
klasy. To jest wersja bezpieczna wątkowoArrayList
.źródło
ConcurrentLinkedQueue
Być może używasz złego podejścia. Tylko dlatego, że jeden wątek symulujący samochód kończy się przed innym wątkiem z symulacją samochodu, nie oznacza, że pierwszy wątek powinien wygrać symulowany wyścig.
To zależy w dużej mierze od twojej aplikacji, ale może być lepiej mieć jeden wątek, który oblicza stan wszystkich samochodów w małych odstępach czasu do zakończenia wyścigu. Lub, jeśli wolisz korzystać z wielu wątków, możesz kazać każdemu samochodowi zarejestrować „symulowany” czas potrzebny do ukończenia wyścigu i wybrać zwycięzcę jako zwycięzcę z najkrótszym czasem.
źródło
Możesz również użyć
synchronized
słowa kluczowego dlaaddFinisher
metody takiej jak ta//Implement the one method in the RaceListener interface public synchronized void addFinisher(RaceCar finisher) { finishingOrder.add(finisher); }
Możesz więc w ten sposób użyć ArrayList dodać metodę bezpieczną dla wątków.
źródło
final Object
każdym razem, gdyCollection
w jakikolwiek sposób uzyskujesz dostęp do .Zawsze, gdy chcesz użyć bezpiecznej dla wątków wersji obiektu kolekcji Ant, skorzystaj z pomocy pakietu java.util.concurrent. * . Ma prawie wszystkie współbieżne wersje niezsynchronizowanych obiektów kolekcji. np. dla ArrayList masz java.util.concurrent.CopyOnWriteArrayList
Możesz zrobić Collections.synchronizedCollection (dowolny obiekt kolekcji), ale pamiętaj o tym klasycznym synchr. technika jest kosztowna i wiąże się z nadwyżką wydajności. Pakiet java.util.concurrent. * jest tańszy i lepiej zarządza wydajnością za pomocą mechanizmów takich jak
Dlatego wolę coś z pakietu java.util.concurrent. *
źródło
Zamiast tego można również użyć jako Vector, ponieważ wektory są bezpieczne dla wątków, a lista arraylist nie. Chociaż wektory są stare, ale mogą łatwo rozwiązać twój cel.
Ale możesz zsynchronizować Arraylist jak kod, pod warunkiem, że:
Collections.synchronizedList(new ArrayList(numberOfRaceCars()));
źródło
Możesz zmienić typ ArrayList na Vector, w którym każda metoda jest synchronizowana.
private Vector finishingOrder; //Make a Vector to hold RaceCar objects to determine winners finishingOrder = new Vector(numberOfRaceCars);
źródło