2009-12-05 6 views
8

Ich habe zwei Arrays, und ich muss den Zugriff auf sie über Threads synchronisieren. Ich werde sie in einen synchronisierten Block stellen. Das Problem ist, ich kann nur einen von ihnen auf "synchronisiert" gehen.Java synchronisierter Block für mehr als 1 Objekte?

Wie stelle ich sicher, dass der Zugriff auf beide Arrays synchronisiert ist? Gebe ich sie in eine Klasse und erstelle ein Objekt davon? Oder ich greife auf das andere Array nur im synchronisierten Block zu, und dies sorgt für den synchronisierten Zugriff darauf?

Danke,

+0

Wenn Sie sie in eine neue Klasse einfügen, kann das helfen, zu klären, was Sie tun möchten, also würde ich das empfehlen. Das hat jedoch keinen Einfluss auf die Thread-Sicherheit. Ich mag die Antwort, die explizite Sperren verwendet (unten). –

Antwort

20

Was auch immer Sie tun dies nicht tun:

synchronized (array1) { 
    synchronized (array2) { 
    // do stuff 
    } 
} 

Dies dürfte zu deadlock führen, wenn Sie sehr vorsichtig sind. Wenn Sie diesen Ansatz verfolgen, müssen Sie sicherstellen, dass Sie eine unveränderliche Teilaufgabe an den Objekten haben - Google "Dining Philosophers" für die Diskussion der Fallstricke.

Im Grunde, was Sie tun müssen, ist ein Schloss-Objekt erstellen, die Sie verwenden, wenn Sie entweder Array zugreifen möchten, und dass dann für alle Zugang Array. Es ist grobkörnig, aber sicher. Man könnte es auf diese Weise tun:

public static class TwoArrays { 
    private int[] array1 = ... 
    private int[] array2 = ... 
    private final Object LOCK = new Object(); 

    public void doUpdate() { 
    synchronized (LOCK) { 
     ... 
    } 
    } 
} 

Wenn Sie eine feinere Methode benötigen Sie die Java 5+ gleichzeitigen Dienstprogramme wie ReadWriteLock verwenden mögen, aber das wird noch komplizierter zu implementieren und zu fehleranfällig.

+1

Sie können auch 'doUpdate' synchronisieren, anstatt die zusätzliche Komplexität des 'LOCK'-Objekts zu haben. – skaffman

+3

Eigentlich nein, es ist das beste Verfahren, Ihre Schlösser nicht freizulegen, was Sie tun, wenn Sie dies als Schloss verwenden. – cletus

+0

Dies führt zu einer Frage - die Verwendung des verschachtelten synchronisierten Blocks kann zu einem Deadlock führen, falls eine weitere Synchronisation für dieselben Objekte stattfindet. Aber würde es passieren, wenn nur der obige Code vorhanden ist? Kein Thread könnte den Monitor von Array2 erfassen, wenn er nicht bereits den Monitor von Array1 besitzt. Und wenn es den Monitor von Array1 hat, kann kein anderer Thread den Monitor von Array2 haben. Habe ich ein Loch in meine Argumentation? – Bozho

11

Vor Java 5, habe ich geschrieben hatte, Dinge wie diese:

// pre Java 5 code: 
Object lock = new Object(); 
// ... 
synchronized(lock) { 
    // do something that requires synchronized access 
} 

Aber da Java 5, I-Klassen von java.util.concurrent.locks verwenden würde (ich persönlich finde das nicht komplizierter oder Fehler -prone):

// Java 5 Code Using Locks 
Lock lock = // ... 
lock.lock(); 
try { 
    // do something that requires synchronized access 
} 
finally { 
    lock.unlock(); 
} 

Wenn Sie Lese-Schreib benötigen Verriegelung, ist hier beispielsweise implementiert Lese-Schreibsperren von Java 5:

private ReadWriteLock rwl = new ReentrantReadWriteLock(); 
private Lock rLock = rwl.readLock(); 
private Lock wLock = rwl.writeLock(); 

private List<String> data = new ArrayList<String>(); 

public String getData(int index) { 
    rLock.lock(); 
    try { 
     return data.get(index); 
    } finally { 
     rLock.unlock(); 
    } 
} 

public void addData(int index, String element) { 
    wLock.lock(); 
    try { 
     data.add(index, element); 
    } finally { 
     wLock.unlock(); 
    } 
} 

Natürlich passen Sie es an Ihre Bedürfnisse an.