2017-07-12 4 views
0

Ich habe eine Liste, ich muss die Liste von zwei Threads durchlaufen. Eine Lesung von oben nach unten und eine andere von unten nach oben. Und wenn sie sich schneiden, sollte das Lesen aufhören.Zwei Threads lesen die gleiche Liste aber von verschiedenen Enden

Zum Iterieren über die Liste kann ich ListIterator verwenden, aber ich bin nicht in der Lage zu denken, wie diese Threads aus derselben Liste lesen werden?

+1

was bedeuten u ', wie man lesen aus derselben Liste? eine Referenz der Liste an beide Threads übergeben? – Yazan

+1

Bearbeiten die Threads die Liste? Wie genau muss das Stoppen sein? Wenn beispielsweise die Threads nach der Überschneidung ein paar weitere Elemente lesen, wäre das schlecht? –

+0

@ThijsSteel, Es werden keine Themen aus der Liste angezeigt. Ja, es ist schlecht, nach der Überschneidung Objekte zu lesen. Ziel ist es also, die ganze Liste zu lesen, aber von verschiedenen Enden ohne zu intervenieren. – Rogger296

Antwort

1

Da die Threads nur gelesen werden, ist es nicht erforderlich, eine Thread-sichere Version der Liste zu verwenden.

Um sicherzustellen, dass die Threads nicht mehr lesen, wenn sie sich schneiden, müssen Sie sie synchronisieren. Bevor Sie also ein anderes Element lesen, sollten Sie prüfen, ob dieses Objekt verfügbar ist. Eine naive Möglichkeit, dies zu implementieren, besteht darin, den aktuellen Index in jedem Thread zu speichern und dem anderen Thread Zugriff auf diesen Index zu gewähren (stellen Sie sicher, dass dieser Index synchronisiert wird). Dies würde jedoch zu viel Overhead führen.

Eine bessere Idee ist es, in Batches zu arbeiten. Unterteilen Sie die Liste in Abschnitte von beispielsweise 16 Elementen. Dann können die Threads die gesamte Charge lesen, bevor sie nach einer Kreuzung suchen müssen.

+0

+1 für "Batching" @ Rogger296, vorausgesetzt, dass der Grund für die Verwendung von zwei Threads ist, eine Berechnung zu beschleunigen, je mehr Arbeit, die die Threads zwischen Synchronisationspunkten tun können, desto mehr Nutzen erhalten Sie von der Verwendung mehrerer Threads. Anfänger sind oft bestürzt zu erfahren, dass schlecht entworfene Multithread-Berechnungen - zu viel Kopplung zwischen Threads - geringer sein können als die Singlethread-Version. –

+0

Die Liste, die ich hier verwende, hat die Dateigröße als Attribut. Und auf der Grundlage der Liste ist absteigend sortiert. Der Thread T1, der von oben gelesen wird, bewegt sich daher langsam, da er schwere Dateien verarbeiten muss, während Thread T2 sich schnell bewegt, da er von unten in der Liste liest, wo die Dateigröße sehr niedrig ist. Ich kann den Stapel nicht verwenden, da er den Thread T1 mit einem umfangreichen Satz von Dateien lädt. Voraussetzung ist also jedes Mal, dass Threads ein einzelnes Element aus der Liste bekommen. – Rogger296

+0

@ Rogger296 Sie könnten Thread 1 in Batch-Größe 1 oder 2 arbeiten und Thread 1 in einer größeren Batch-Größe arbeiten. Sie könnten sogar die Batch-Größe im laufenden Betrieb anpassen. –

0

Sie können die Liste partitionieren, die ein Thread von 0 bis zur Hälfte lesen wird und die zweite wird die Hälfte + 1 für die letzte lesen.

class PrintList implements Runnable{ 

    private List list = new ArrayList(); 
    public PrintList(List list){ 
     this.list = list; 
    } 


    @Override 
    public void run() { 
    if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread1")){ 
     int mid =list.size()/2; 
     for(int i = 0; i< mid;i++){ 
      // System.out.println("Thread 1 "+list.get(i)); 
     } 
    }else if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread2")){ 

     for(int i = mid; i<list.size(); i++){ 
      //System.out.println("Thread 2 "+list.get(i)); 
     } 
    } 
    } 
} 
+0

Es ist nicht erforderlich, die Liste zu partitionieren, sondern sie mit zwei Threads gleichzeitig zu lesen. T1 von oben und T2 von unten. Die Liste ist in absteigender Reihenfolge sortiert, so dass T1 schwere Dateien liest und T2 kleinere Dateien liest. – Rogger296

0

Es gibt eine einfache Möglichkeit, dieses Problem zu lösen, wenn Sie berücksichtigen, dass die Gesamtzahl der Elemente von Thread A verarbeitet und die Summe durch Gewinde B verarbeitet Elemente werden am Ende auf die Menge der Elemente in der gleich Liste.

Wenn Sie also einen Zähler haben, der jedes Mal dekrementiert, wenn ein Thread das nächste Element verarbeiten möchte, wissen Sie, dass Sie fertig sind, sobald der Zähler Null erreicht.

public class MyThreadSyncer { 
    protected final AtomicInteger elementCount; 

    public MyThreadSyncer(final Collection c) { 
    elementCount = new AtomicInteger(c.size()); 
    } 

    public boolean canProcessNext() { 
    return (this.elementCount.decrementAndGet() >= 0); 
    } 
} 

diese Klasse Mit jedem Thread über einen eigenen Zähler setzt (Thread A bei 0, Gewinden B bei Größe-1) und prüft dann wie folgt aus:

if (this.threadSyncer.canProcessNext()) { 
    this.theTasks[this.myPosition].process(); 

    this.myPosition += 1; // this line in thread A 
    this.myPosition -= 1; // this line in thread B 
} 
Verwandte Themen