2016-04-27 14 views
1

Gibt es eine saubere und effiziente Möglichkeit, ein Atomic(Double|Integer|Long|Reference)Array zu wachsen? In meinem speziellen Fall gibt es keine gleichzeitigen Schreibvorgänge während des Kopierens. Ein offensichtlicher Weg, um einen neuen und kopieren Sie den Quell-Array an den Ziel-Array in einer Schleife zu erstellen:effizient wachsende atomare Arrays

Atomic*Array dest = new Atomic*Array(newSize); 
for (int i = 0, len = src.length(); i < len; ++i) 
    dest.set(i, src.get(i)); 

Dieser Code ist wahrscheinlich viel langsamer als eine System.arraycopy oder Arrays.copy Typ Funktion und ist auch ein bisschen ausführlicher.

I Reflexion abwechselnd die Quelle des verwenden könnte array Feld zu bekommen, verlängern sie, und das neue Array in das Array-Konstruktor Atomic * übergeben:

try { 
    Field arrayField = Atomic*Array.class.getDeclaredField("array"); 
    arrayField.setAccessible(true); 
    ArrayType srcArray = (ArrayType)arrayField.get(src); 
    Atomic*Array dest = new Atomic*Array(Arrays.copyOf(srcArray, newLength)); 
} catch (IllegalAccessException | NoSuchFieldException e) { 
    throw new AssertionError(e); 
} 

Aber dieser Code hat auch Probleme: es über die Umsetzung hängt der Klasse, macht zwei Kopien des Arrays - eine in Arrays.copy und eine in dest Konstruktor, und ist sehr hässlich.

Gibt es einen schnelleren/saubereren Weg, dies zu tun?

+0

Verbunden: http://StackOverflow.com/Questions/9408112/get-the-array-from-anatomiclongarray –

+0

Sie können wachsen, indem Sie vom alten zum neuen Array verbinden, damit Verbraucher durchqueren können. Siehe JCTools '[MpscChunkedArrayQueue] (https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/MpscChunkedArrayQueue.java) für ein Beispiel dieser Idee. –

+0

@BenManes Ja, ich dachte an diese Idee, aber dann ist die Speichernutzung wesentlich höher, da wir Arrays in Links einbinden müssen, und die Logik ist etwas komplexer, weil wir einen ungefähren Tail-Zeiger beibehalten müssen. Da die Dinge anständig mit einem einzigen Array funktionieren, möchte ich so viel Leistung wie möglich aus dieser Methode herausholen. –

Antwort

1

Ich bin besorgt, ich werde dich enttäuschen: Es gibt keine Möglichkeit, Atomic*Array im Batch zu kopieren.

Wenn Sie javadoc betrachten, gibt es keine Methode, die Ihnen mehr als ein einzelnes Element gleichzeitig geben würde. Nicht einmal die Verwendung des ursprünglichen Arrays, das an AtomicIntegerArray übergeben werden kann, würde helfen - die Klasse erstellt intern eine Kopie.

Betrachtet man AtomicIntegerArray Quellcode, könnte die Verwendung von Reflektion funktionieren - die Klasse macht nichts Besonderes mit dem Feld array. Ich würde es aber nicht tun. Es ist nicht nur sicher, sondern auch Reflektion wird Ihnen einige Leistungseinbußen geben, die Sie vermeiden möchten.

Wenn es Ihr Ziel ist, das Array zu vergrößern, können Sie sich je nach Anwendungsfall LinkedBlockingQueue oder CopyOnWriteArrayList ansehen.

Ich habe ein paar Mal in dieses Problem gelaufen und wir fanden am Ende immer einen Weg ohne Atomic*Array.

+0

Danke. Mein Ziel ist es, eine sehr speichereffiziente, nicht blockierende Append-Only-Liste zu implementieren. Aber leider erfüllt weder 'LinkedBlockingQueue' noch' CopyOnWriteArrayList' meine Bedürfnisse: Ersteres verwendet viel zu viel Speicher für seine Knoten und Letzteres ist extrem ineffizient. Tatsächlich entspricht keine Sammlung in der Standardbibliothek meinen Anforderungen. –

+0

Schade, dass Sie die "non-blocking" -Anforderung hinzugefügt haben, sonst könnten Sie auch mit dem guten alten 'synchronisierten' machen. – Mifeet

+0

Richtig,' Collections.synchronizedList (new ArrayList <>()) 'würde funktionieren, aber nicht blockierend ist weit vorzuziehen, da es in der überwiegenden Mehrheit der Fälle keine Konkurrenz gibt und somit wesentlich schneller ist (auch beim Wachsen durch Kopieren in eine Schleife :)). –

Verwandte Themen