Mam 2 macierze i muszę je pomnożyć, a następnie wydrukować wyniki z każdej komórki. Jak tylko jedna komórka jest gotowa, muszę ją wydrukować, ale na przykład muszę wydrukować komórkę [0] [0] przed komórką [2] [0], nawet jeśli wynik [2] [0] jest najpierw gotowy . Więc muszę to wydrukować na zamówienie. Więc moim pomysłem jest, aby wątek drukarki czekał, aż multiplyThread
powiadomi go, że właściwa komórka jest gotowa do wydrukowania, a następnie printerThread
wydrukuje komórkę i wróci do oczekiwania i tak dalej.
Więc mam ten wątek, który wykonuje mnożenie:
public void run()
{
int countNumOfActions = 0; // How many multiplications have we done
int maxActions = randomize(); // Maximum number of actions allowed
for (int i = 0; i < size; i++)
{
result[rowNum][colNum] = result[rowNum][colNum] + row[i] * col[i];
countNumOfActions++;
// Reached the number of allowed actions
if (countNumOfActions >= maxActions)
{
countNumOfActions = 0;
maxActions = randomize();
yield();
}
}
isFinished[rowNum][colNum] = true;
notify();
}
Wątek, który drukuje wynik każdej komórki:
public void run()
{
int j = 0; // Columns counter
int i = 0; // Rows counter
System.out.println("The result matrix of the multiplication is:");
while (i < creator.getmThreads().length)
{
synchronized (this)
{
try
{
this.wait();
}
catch (InterruptedException e1)
{
}
}
if (creator.getmThreads()[i][j].getIsFinished()[i][j] == true)
{
if (j < creator.getmThreads()[i].length)
{
System.out.print(creator.getResult()[i][j] + " ");
j++;
}
else
{
System.out.println();
j = 0;
i++;
System.out.print(creator.getResult()[i][j] + " ");
}
}
}
Teraz rzuca mi te wyjątki:
Exception in thread "Thread-9" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-6" Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-5" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
wiersz 49 w multiplyThread
to „notify ()”. Myślę, że muszę inaczej używać synchronizacji, ale nie jestem pewien, jak to zrobić.
Jeśli ktoś może pomóc temu kodowi działać, to naprawdę to docenię.
źródło
while(!JobCompleted);
opcja jest ogólnie złym pomysłem, ponieważ wiąże procesor w 100%, sprawdzając stale tę samą zmienną (patrz tutaj )while(!JobCompleted) Thread.sleep(5);
nie ma tego problemuwait
gdy bieżący wątek ma blokadę nawait
wywołanym obiekcie . To, czy użyjeszsynchronized
bloku, czy metody zsynchronizowanej, zależy wyłącznie od Ciebie.Korzystając z metod
wait
inotify
lubnotifyAll
w Javie należy pamiętać o następujących rzeczach:notifyAll
zamiast,notify
jeśli spodziewasz się, że więcej niż jeden wątek będzie czekał na blokadę.wait
Inotify
metody muszą być nazywane w zsynchronizowany kontekście . Zobacz łącze, aby uzyskać bardziej szczegółowe wyjaśnienie.wait()
metodę w pętli, ponieważ jeśli wiele wątków czeka na blokadę, a jeden z nich otrzymał blokadę i zresetował warunek, pozostałe wątki muszą sprawdzić stan po przebudzeniu, aby zobaczyć, czy muszą ponownie czekać, czy można rozpocząć przetwarzanie.wait()
inotify()
metody; każdy obiekt ma własną blokadę, więc wywołaniewait()
obiektu A inotify()
obiektu B nie będzie miało żadnego sensu.źródło
Czy w ogóle musisz to wątkować? Zastanawiam się, jak duże są twoje macierze i czy jest jakaś korzyść z drukowania jednego wątku, podczas gdy drugi wykonuje mnożenie.
Może warto byłoby zmierzyć ten czas przed wykonaniem stosunkowo złożonej pracy związanej z gwintowaniem?
Jeśli potrzebujesz wątku, utworzę wątki `` n '', aby wykonać mnożenie komórek (być może `` n '' to liczba dostępnych rdzeni), a następnie użyj mechanizmu ExecutorService i Future do jednoczesnego wysłania wielu mnożeń .
W ten sposób możesz zoptymalizować pracę w oparciu o liczbę rdzeni i używasz wyższego poziomu narzędzi do obsługi wątków Java (co powinno ułatwić życie). Zapisz wyniki z powrotem do matrycy odbiorczej, a następnie po prostu wydrukuj ją po zakończeniu wszystkich zadań w przyszłości.
źródło
Powiedzmy, że masz aplikację „czarną skrzynkę” z klasą o nazwie,
BlackBoxClass
która ma metodędoSomething();
.Ponadto masz nazwanego obserwatora lub słuchacza,
onResponse(String resp)
który zostanie wywołanyBlackBoxClass
po nieznanym czasie.Przepływ jest prosty:
private String mResponse = null; ... BlackBoxClass bbc = new BlackBoxClass(); bbc.doSomething(); ... @override public void onResponse(String resp){ mResponse = resp; }
Powiedzmy, że nie wiemy, co się dzieje
BlackBoxClass
i kiedy powinniśmy otrzymać odpowiedź, ale nie chcesz kontynuować kodu, dopóki nie otrzymasz odpowiedzi lub innymi słowy nieonResponse
zadzwonisz. Tutaj wchodzi „Synchronizuj pomocnika”:public class SyncronizeObj { public void doWait(long l){ synchronized(this){ try { this.wait(l); } catch(InterruptedException e) { } } } public void doNotify() { synchronized(this) { this.notify(); } } public void doWait() { synchronized(this){ try { this.wait(); } catch(InterruptedException e) { } } } }
Teraz możemy wdrożyć to, co chcemy:
public class Demo { private String mResponse = null; ... SyncronizeObj sync = new SyncronizeObj(); public void impl(){ BlackBoxClass bbc = new BlackBoxClass(); bbc.doSomething(); if(mResponse == null){ sync.doWait(); } /** at this momoent you sure that you got response from BlackBoxClass because onResponse method released your 'wait'. In other cases if you don't want wait too long (for example wait data from socket) you can use doWait(time) */ ... } @override public void onResponse(String resp){ mResponse = resp; sync.doNotify(); } }
źródło
Powiadomienia możesz wywoływać tylko w przypadku obiektów, do których posiadasz ich monitor. Więc potrzebujesz czegoś takiego
synchronized(threadObject) { threadObject.notify(); }
źródło
notify()
również musi zostać zsynchronizowanyźródło
Prawidłowy prosty przykład pokażę ci właściwy sposób używania
wait
inotify
w Javie. Więc utworzę dwie klasy o nazwach ThreadA i ThreadB . ThreadA wywoła ThreadB.public class ThreadA { public static void main(String[] args){ ThreadB b = new ThreadB();//<----Create Instance for seconde class b.start();//<--------------------Launch thread synchronized(b){ try{ System.out.println("Waiting for b to complete..."); b.wait();//<-------------WAIT until the finish thread for class B finish }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("Total is: " + b.total); } } }
a dla klasy ThreadB:
class ThreadB extends Thread{ int total; @Override public void run(){ synchronized(this){ for(int i=0; i<100 ; i++){ total += i; } notify();//<----------------Notify the class wich wait until my finish //and tell that I'm finish } } }
źródło
Proste użycie, jeśli chcesz Jak alternatywnie wykonywać wątki: -
public class MyThread { public static void main(String[] args) { final Object lock = new Object(); new Thread(() -> { try { synchronized (lock) { for (int i = 0; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + "A"); lock.notify(); lock.wait(); } } } catch (Exception e) {} }, "T1").start(); new Thread(() -> { try { synchronized (lock) { for (int i = 0; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + "B"); lock.notify(); lock.wait(); } } } catch (Exception e) {} }, "T2").start(); } }
źródło
możemy wywołać powiadomienie, aby wznowić wykonywanie oczekujących obiektów jako
public synchronized void guardedJoy() { // This guard only loops once for each special event, which may not // be the event we're waiting for. while(!joy) { try { wait(); } catch (InterruptedException e) {} } System.out.println("Joy and efficiency have been achieved!"); }
wznowić to przez wywołanie powiadomienia na innym obiekcie tej samej klasy
public synchronized notifyJoy() { joy = true; notifyAll(); }
źródło
W przypadku tego konkretnego problemu dlaczego nie przechowywać różnych wyników w zmiennych, a następnie po przetworzeniu ostatniego wątku można drukować w dowolnym formacie. Jest to szczególnie przydatne, jeśli będziesz używać swojej historii pracy w innych projektach.
źródło
Wygląda to na sytuację dla wzorca producent-konsument. Jeśli korzystasz z Java 5 lub nowszej, możesz rozważyć użycie kolejki blokującej (java.util.concurrent.BlockingQueue) i pozostawić koordynację wątków do podstawowej implementacji frameworka / interfejsu API. Zobacz przykład z java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html lub java 7 (ten sam przykład): http: // docs. oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html
źródło
Prawidłowo zabezpieczyłeś swój blok kodu podczas wywoływania
wait()
metody przy użyciusynchronized(this)
.Ale nie podjąłeś tych samych środków ostrożności, gdy wywołujesz
notify()
metodę bez użycia chronionego bloku:synchronized(this)
lubsynchronized(someObject)
Jeśli znajdują się na stronie dokumentacji systemu Oracle obiektu klasy, która zawiera
wait()
,notify()
,notifyAll()
metody, można zobaczyć poniżej ostrożności we wszystkich tych trzech metodWiele rzeczy zostało zmienionych w ciągu ostatnich 7 lat i spójrzmy na inne alternatywy dla
synchronized
poniższych pytań SE:Po co używać ReentrantLock, jeśli można używać zsynchronizowanego (tego)?
Synchronizacja a blokada
Unikać synchronizacji (this) w Javie?
źródło