[java] ArrayList를 스레드로부터 안전하게 만들려면 어떻게합니까? Java의 문제에 대한 또 다른 접근 방식?

실행이 완료되는 즉시 Thread 클래스를 확장하는 RaceCar 개체를 유지하는 데 사용하려는 ArrayList가 있습니다. Race라고하는 클래스는 RaceCar 객체가 실행이 끝나면 호출하는 콜백 메서드를 사용하여이 ArrayList를 처리합니다. 콜백 메서드 인 addFinisher (RaceCar finisher)는 RaceCar 객체를 ArrayList에 추가합니다. 이것은 스레드가 실행을 완료하는 순서를 제공합니다.

ArrayList가 동기화되지 않았으므로 스레드로부터 안전하지 않습니다. 새 ArrayList를 전달하고 반환 된 Collection을 ArrayList에 할당하여 Collections.synchronizedCollection (c Collection) 메서드를 사용해 보았습니다. 그러나 이것은 나에게 컴파일러 오류를 제공합니다.

Race.java:41: incompatible types
found   : java.util.Collection
required: java.util.ArrayList
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));

다음은 관련 코드입니다.

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);
    }

내가 알아야 할 것은 올바른 접근 방식을 사용하고 있는지, 그렇지 않은 경우 코드를 스레드로부터 안전하게 만들기 위해 무엇을 사용해야합니까? 도와 주셔서 감사합니다!



답변

사용 Collections.synchronizedList().

전의:

Collections.synchronizedList(new ArrayList<YourClassNameHere>())


답변

변화

private ArrayList finishingOrder;

//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars)

…에

private List finishingOrder;

//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedList(new ArrayList(numberOfRaceCars)

List는 ArrayList의 상위 유형이므로이를 지정해야합니다.

그렇지 않으면 당신이하고있는 일이 괜찮아 보입니다. 다른 옵션은 동기화 된 Vector를 사용할 수 있다는 것입니다.하지만 이것이 아마도 제가 할 일입니다.


답변

CopyOnWriteArrayList

CopyOnWriteArrayList수업을 사용하십시오 . 이것은의 스레드로부터 안전한 버전입니다 ArrayList.


답변

당신은 수있는 잘못된 방법을 사용합니다. 자동차를 시뮬레이션하는 스레드 하나가 다른 자동차 시뮬레이션 스레드보다 먼저 완료된다고해서 첫 번째 스레드가 시뮬레이션 된 레이스에서 승리해야한다는 의미는 아닙니다.

애플리케이션에 따라 많이 다르지만 레이스가 완료 될 때까지 작은 시간 간격으로 모든 자동차의 상태를 계산하는 하나의 스레드를 갖는 것이 더 나을 수 있습니다. 또는 여러 스레드를 사용하는 것을 선호하는 경우 각 자동차가 레이스를 완료하는 데 걸린 “시뮬레이션 된”시간을 기록하고 가장 짧은 시간에 승자를 선택하도록 할 수 있습니다.


답변

이와 같은 방법으로 synchronized키워드를 사용할 수도 있습니다.addFinisher

    //Implement the one method in the RaceListener interface
    public synchronized void addFinisher(RaceCar finisher) {
        finishingOrder.add(finisher);
    }

따라서이 방법으로 ArrayList add 메서드를 스레드로부터 안전하게 사용할 수 있습니다.


답변

ant 컬렉션 객체의 ant thread safe 버전을 사용하려면 java.util.concurrent. * 패키지의 도움을 받으십시오 . 동기화되지 않은 컬렉션 개체의 거의 모든 동시 버전이 있습니다. 예 : ArrayList의 경우 java.util.concurrent.CopyOnWriteArrayList가 있습니다.

Collections.synchronizedCollection (모든 컬렉션 객체)을 수행 할 수 있지만이 고전적인 동기화를 기억하십시오. 기술은 비싸고 성능 오버 헤드가 있습니다. java.util.concurrent. * 패키지는 저렴하며 다음과 같은 메커니즘을 사용하여 더 나은 방식으로 성능을 관리합니다.

쓰기시 복사, 비교 및 ​​교체, 잠금, 스냅 샷 반복기 등

그래서, java.util.concurrent. * 패키지에서 무언가를 선호하십시오


답변

벡터는 스레드로부터 안전하고 arraylist는 그렇지 않으므로 대신 Vector로 사용할 수도 있습니다. 벡터는 오래되었지만 목적을 쉽게 해결할 수 있습니다.

그러나 다음과 같은 코드처럼 Arraylist를 동기화 할 수 있습니다.

Collections.synchronizedList(new ArrayList(numberOfRaceCars()));