J'ai 2 matrices et je dois les multiplier, puis imprimer les résultats de chaque cellule. Dès qu'une cellule est prête, je dois l'imprimer, mais par exemple, je dois imprimer la cellule [0] [0] avant la cellule [2] [0] même si le résultat de [2] [0] est prêt en premier. . J'ai donc besoin de l'imprimer par commande. Donc, mon idée est de faire en sorte que le fil d'impression attende que le multiplyThread
lui notifie que la bonne cellule est prête à être imprimée, puis le printerThread
imprimera la cellule et reviendra en attente, etc.
J'ai donc ce fil qui fait la multiplication:
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();
}
Fil qui affiche le résultat de chaque cellule:
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] + " ");
}
}
}
Maintenant, il me jette ces exceptions:
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)
la ligne 49 dans multiplyThread
est "notify ()" .. Je pense que je dois utiliser le mode synchronisé différemment, mais je ne sais pas comment.
Si quelqu'un peut aider ce code à fonctionner, je l'apprécierai vraiment.
Pour pouvoir appeler notify () vous devez vous synchroniser sur le même objet.
synchronized (someObject) {
someObject.wait();
}
/* different thread / object */
synchronized (someObject) {
someObject.notify();
}
Lorsque vous utilisez les méthodes wait
et notify
ou notifyAll
dans Java, vous devez vous rappeler les points suivants:
notifyAll
au lieu de notify
si vous vous attendez à ce que plusieurs threads attendent un verrou.wait
et notify
doivent être appelées dans un contexte synchronisé . Voir le lien pour une explication plus détaillée.wait()
dans une boucle, car si plusieurs threads attendent un verrou et l’un d’eux a le verrouillé et réinitialise la condition, les autres threads doivent alors vérifier la condition après leur réveil pour voir s’ils se réveillent. besoin d'attendre encore ou peut commencer le traitement.wait()
et notify()
; chaque objet a son propre verrou donc appeler wait()
sur l'objet A et notify()
sur l'objet B n'aura aucun sens.Avez-vous besoin d'enfiler ça du tout? Je me demande quelle est la taille de vos matrices et s'il y a un avantage à avoir un fil imprimé pendant que l'autre effectue la multiplication.
Peut-être vaudrait-il la peine de mesurer ce temps avant d’effectuer le travail de filetage relativement complexe?
Si vous avez besoin de le filer, je créerais des "n" fils pour effectuer la multiplication des cellules (peut-être que "n" est le nombre de cœurs disponibles), puis utiliser ExecutorService et Future mécanisme d'envoi simultané de multiples multiplications.
De cette façon, vous pouvez optimiser le travail en fonction du nombre de cœurs et utiliser les outils de filetage de niveau supérieur Java (qui devraient vous simplifier la vie). Ecrivez les résultats dans une matrice de réception, puis imprimez-les simplement une fois que toutes vos tâches futures sont terminées.
Supposons que vous ayez une application 'boîte noire' avec une classe nommée BlackBoxClass
utilisant la méthode doSomething();
.
De plus, vous avez un observateur ou un auditeur nommé onResponse(String resp)
qui sera appelé par BlackBoxClass
après un temps inconnu.
Le flux est simple:
private String mResponse = null;
...
BlackBoxClass bbc = new BlackBoxClass();
bbc.doSomething();
...
@override
public void onResponse(String resp){
mResponse = resp;
}
Disons que nous ne savons pas ce qui se passe avec BlackBoxClass
et quand nous devrions obtenir une réponse, mais vous ne voulez pas continuer votre code tant que vous n'avez pas reçu de réponse ou dans un autre mot, appelez onResponse
. Ici entre 'Synchronize helper':
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) {
}
}
}
}
Maintenant, nous pouvons mettre en œuvre ce que nous voulons:
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();
}
}
Vous pouvez uniquement appeler notify sur les objets pour lesquels vous possédez leur moniteur. Donc vous avez besoin de quelque chose comme
synchronized(threadObject)
{
threadObject.notify();
}
notify()
doit également être synchronisé
Je vais vous donner un exemple simple et vous montrer comment utiliser wait
et notify
en Java. Je vais donc créer deux classes nommées ThreadA & ThreadB. ThreadA appellera 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);
}
}
}
et pour la classe 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
}
}
}
Utilisation simple si vous voulez Comment exécuter des threads alternativement: -
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éponse: -
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
nous pouvons appeler notify pour reprendre l'exécution d'objets en attente comme
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!");
}
résumez ceci en appelant notify sur un autre objet de la même classe
public synchronized notifyJoy() {
joy = true;
notifyAll();
}
Pour ce problème particulier, pourquoi ne pas stocker vos différents résultats dans des variables et ensuite, lorsque le dernier de vos threads est traité, vous pouvez imprimer dans le format de votre choix. Ceci est particulièrement utile si vous utilisez votre historique de travail dans d’autres projets.
Vous avez correctement protégé votre bloc de code lorsque vous appelez la méthode wait()
à l'aide de synchronized(this)
.
Mais vous n’avez pas pris la même précaution lorsque vous appelez la méthode notify()
sans utiliser de bloc protégé: synchronized(this)
ou synchronized(someObject)
Si vous vous référez à la page de documentation Oracle sur la classe Object , qui contient les méthodes wait()
, notify()
, notifyAll()
, vous pouvez voir ci-dessous les précautions d'utilisation de ces trois méthodes.
Cette méthode ne doit être appelée que par un thread propriétaire du moniteur de cet objet.
Beaucoup de choses ont été changées au cours des 7 dernières années et examinons d'autres alternatives à synchronized
dans les questions SE suivantes:
Pourquoi utiliser un ReentrantLock si on peut utiliser synchronisé (ceci)?
Cela ressemble à une situation pour le modèle producteur-consommateur. Si vous utilisez Java 5 ou version ultérieure, vous pouvez envisager d’utiliser une file d’attente (Java.util.concurrent.BlockingQueue) et laisser le travail de coordination des threads à l’implémentation framework/api sous-jacent. Voir l'exemple de Java 5: http://docs.Oracle.com/javase/1.5.0/docs/api/Java/util/concurrent/BlockingQueue.html ou Java 7 (même exemple): http://docs.Oracle.com/javase/7/docs/api/Java/util/concurrent/BlockingQueue.html