Problema di threading Java
-
20-09-2019 - |
Domanda
Sto usando più thread nella mia applicazione. Fondamentalmente ho una casella combinata e dopo aver selezionato la posta in arrivo, P1 riprende e P2 viene sospeso e dopo la selezione di invio, p2 avvia e p1 si fermano. Di seguito è riportato il codice (sono sicuro che non è perfetto)
public void modifyText(ModifyEvent e) {
if (combo.getText().equals("Inbox"))
{
synchronized(p2)
{
p2.cont = false;
}
table.removeAll();
synchronized(p1)
{
p1.cont = true;
p1.notify();
}
}
else if (combo.getText().equals("Sent"))
{
synchronized(p2)
{
p1.cont = false;
}
table.removeAll();
synchronized(p1)
{
p2.cont = true;
p2.notify();
}
}
}
});
E per P1 e P2 ho questo all'interno dei loro loop:
synchronized (this) {
while (cont == false)
try {
wait();
} catch (Exception e) {
}
}
... come è ora funziona (sono un principiante per i fili). Durante la pressatura inviata nella scatola combinata, ottengo unastatemonitorexception illegale. Qualcuno potrebbe aiutarmi a risolvere il problema per favore?
Grazie e saluti, krt_malta
Soluzione
Il problema è qui:
synchronized(p1)
{
p2.cont = true;
p2.notify();
}
Stai facendo p2.notify()
Quando non hai un blocco p2
(È necessario tenere il monitor per chiamare Notify su di esso). Modificare synchronized(p1)
a synchronized(p2)
. Inoltre, è necessario invertire anche l'altra clausola sincronizzata che è anche difettosa. Quindi, come esempio:
synchronized(p1)
{
p1.cont = false;
// p1.notify(); <- do you need this here?
}
table.removeAll();
synchronized(p2)
{
p2.cont = true;
p2.notify();
}
Inoltre, anche il tuo altro codice è un po 'sbagliato, è una pessima pratica bloccare all'interno di un intero anello, renderlo un po' più atomico.
while (!cont) {
synchronized (this) {
try {
wait();
} catch (Exception e) {
}
}
}
Ulteriore ottimizzazione, evitare synchronised
se possibile:
if (p1.cont) {
synchronized(p1)
{
p1.cont = false;
// p1.notify(); <- do you need this here?
}
}
table.removeAll();
if (!p2.cont) {
synchronized(p2)
{
p2.cont = true;
p2.notify();
}
}
Crea il campo Cont volatile
Qui, e rispecchiati per l'altra parte dell'istruzione IF, come appropriato.
EDIT: Guardando indietro a questo e combattendo con un bug di concorrenza che stavo affrontando di recente, chiunque implementasse questo modello potrebbe affrontare un problema con un'attesa infinita, se un oggetto è bloccato e mezza bloccato viene esaminato dal condizionale del tempo Loop (questo perché esiste un divario in cui lo stato può cambiare tra la valutazione del condizionale e l'imposizione della dichiarazione di attesa). In questo caso, posizionare il blocco sincronizzato sul fuori del ciclo.
Altri suggerimenti
In questo codice
synchronized(p1)
{
p2.cont = true;
p2.notify();
}
Stai sincronizzando p1
Ma chiamando notify()
Su p2
, il che porta all'eccezione.
Non puoi aspettare nel thread di spedizione di eventi AWT, altrimenti che reggerà l'intera app. Leggi http://en.wikipedia.org/wiki/event_dispatching_thread
Inoltre non dovresti usare i thread grezzi a meno che tu non sappia davvero cosa stai facendo. Guardare http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html e leggi Esecutori