6
votes

Un fil de serrage multiple passe dans l'état d'attente (). Est-ce que ça libère tous les serrures de maintien?

J'ai écrit ce programme pour vérifier si un thread T1 tenant la serrure sur deux objets différents: LOCK.CLASS ET MYTHEAD.CLASS passe en mode attente sur myTythread.Class Instance à l'aide de myThread.class.wait (). Il ne relâche pas verrouillage sur serrure.class Instance. Pourquoi alors? J'ai pensé qu'une fois qu'un fil passe en mode d'attente ou que cela meurt, il libère toutes les serrures acquises.

public class Lock {

protected static volatile boolean STOP = true;
public static void main(String[] args) throws InterruptedException {
    MyThread myThread = new MyThread();
    Thread t1 = new Thread(myThread);
    t1.start();
    while(STOP){
    }
    System.out.println("After while loop");
    /*
     * 
     */
    Thread.sleep(1000*60*2);
    /*
     * Main thread should be Blocked.
     */
    System.out.println("now calling Check()-> perhaps i would be blocked. t1 is holding lock on class instance.");
    check();
}

public static synchronized void check(){
    System.out.println("inside Lock.check()");
    String threadName = Thread.currentThread().getName();
    System.out.println("inside Lock.Check() method : CurrrentThreadName : "+ threadName);
}
}


class MyThread implements Runnable{
public MyThread() {
}

@Override
public void run() {
    try {
        System.out.println("inside Mythread's run()");
        classLocking();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public static synchronized void classLocking() throws InterruptedException{
    System.out.println("inside Mythread.classLocking()");
    String threadName = Thread.currentThread().getName();
    System.out.println("inside MyThread.classLocking() : CurrrentThreadName : "+ threadName);
    /*
     * outer class locking 
     */
    synchronized (Lock.class) {
        System.out.println("I got lock on Lock.class definition");
        Lock.STOP = false;
        /*
         * Outer class lock is not released. Lock on MyThread.class instance is released.
         */
        MyThread.class.wait();
    }
}
}


0 commentaires

4 Réponses :


4
votes

Vous avez raison de ne pas libérer l'autre verrouillage. Quant à pourquoi, c'est parce que ce n'est pas sûr de le faire. S'il était prudent de libérer la serrure extérieure pendant l'appel à la fonction interne, pourquoi la fonction interne serait-elle appelée avec l'autre verrou tenu du tout?

Avoir une fonction Libérer un verrou, il n'a pas acquis derrière le dos du programmeur détruire la logique des fonctions synchronisées.


9 commentaires

.Merci pour votre réponse. Une fois que T1 passe en mode d'attente et non actif, pourquoi est-il enfoncé sur serrure sur serrure.class.


@Manishbhunwal Quand un fil est en train de dormir, cela ne signifie pas que cela perd tout et c'est pourquoi l'impasse pourrait se produire si elle détient une autre serrure et attend sans le libérer.


Une fonction peut en effet facilement libérer un verrou, il n'a pas acquis: annulé synchronisé a () {b (); } vide b () {wait (); } - c'est B qui libère la verrouillage acquis par A .


@Markotopolnik: Droite, mais c'est seulement parce que A et B fait partie de la même interface et doit donc être conçu comme une unité.


@Manishbhunwal: empêcher d'autres threads d'y accéder. Si elle était sûre pour les autres threads d'accéder à l'objet, pourquoi aurait-il eu le pareil?


b () pourrait être n'importe où: Classe publique A {Verrouillage final Static statique L = nouvel objet (); annulation publique a () {synchronisé (l) {b.b (); }}} Classe publique B {Public Static Void B () {A.L.Wait (); }} C'est une conception terrible, mais disprovise votre logique qui parle du comportement spécifié de attendre .


@Markotopolnik: Je ne suis pas en train de suivre la façon dont il disprovise ma logique. Oui, vous pouvez faire quelque chose de stupide si vous essayez assez fort. Cela ne modifie pas les raisons pour lesquelles l'interface est conçue comme elle est. Cela n'applique pas sa justification, mais elle a la raison d'être et est conçue autour de cette justification. Si attendez publié n'importe quel verrou autre que celui spécifié, qui vaincre la justification. Oui, si vous essayez assez fort, vous pouvez vaincre la justification, mais ce n'est pas brisé par la conception.


Dans ce cas, votre dernière phrase n'est tout simplement pas ce que vous vouliez dire.


Je pense que je l'ai clarifié. Merci.



0
votes

La sémantique d'attente () est que le fil invoquant qu'il remarque qu'un verrou était déjà acquis par un autre thread, est suspendu et attend la notification par le fil tenant la serrure lorsque ce dernier le libère (et invoque notifier) . Cela ne signifie pas que tout en attendant qu'il libère tous les serrures acquises. Vous pouvez voir les invocations d'attente en tant que nombre de barrières que le thread se réunit sur le point d'acquérir tous les serrures nécessaires pour accomplir une action.

En ce qui concerne la question "Pourquoi un fil ne libère pas tous les serrures acquis lors de l'invocation attente", je pense que la réponse est que, cela le rendrait plus sujet à la famine et cela ralentirait également les progrès dans un multithread Application (tous les threads abandonneraient toutes leurs serrures lorsqu'ils invoquent la première attente et devraient recommencer lorsqu'ils acquièrent la serrure qu'ils attendent actuellement. Donc, ils seraient dans une bataille permanente pour les serrures. En fait, dans un tel système, le seul fil capable de terminer l'exécution serait celui qui parvient à trouver toutes les serrures libres quand elle en a besoin. Cela est peu probable que cela se produise)


0 commentaires

0
votes

de javadoc de méthode wait ()

Le thread actuel doit posséder le moniteur de cet objet. Le fil libère la propriété de ce moniteur et attend jusqu'à ce qu'un autre thread notifie des threads en attente du moniteur de cet objet pour se réveiller soit via un appel au notifier méthode ou le notifier la méthode . Le fil attend ensuite jusqu'à ce qu'il puisse ré-obtenir la propriété du moniteur et reprendre l'exécution.


0 commentaires

0
votes

Oui, cela fonctionne correctement. Un thread passe dans l'état d'attente libère le verrou correspondant au lieu de tous les verrous. Sinon, réfléchissez-y: si les choses sont comme ce que vous pensiez, alors lorsqu'un fil attend, il perd tous les serrures acquises, ce qui rend une exécution séquentielle avancée impossible.


0 commentaires