2017-01-04 3 views
0

Hinweis Wechsel: Obwohl unter scenariois nicht gültig sind, welches Konzept der synchronisierten Block verletzt, noch zu wissen, habe ich versucht, wie es, wenn soZwei Fäden in synchronisierten Block von Monitor in der Laufzeit

zwei Threads Erstellt arbeitet, Beide Threads versuchen denselben kritischen Abschnitt auszuführen. Überraschenderweise treten beide Threads in den kritischen Abschnitt ein, obwohl sie den Monitor wechseln.

public class MultiThreadTest { 
    final static ConcurrentHashMap<String,Object> objMap = new ConcurrentHashMap<String, Object>(); 

    public static void main(String[] args) { 
     Thread t1 = new Thread(new MyThread(objMap,"1","T1")); 
     Thread t2 = new Thread(new MyThread(objMap,"1","T2")); 
     t1.start(); 
     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException ex) { 
     Logger.getLogger(MultiThreadTest.class.getName()).log(Level.SEVERE,   null, ex); 
    } 
    t2.start(); 
    } 
} 

class MyThread implements Runnable{ 

    private final ConcurrentHashMap<String,Object> objMap; 

    private final String id; 

    private final String name; 

    public MyThread(ConcurrentHashMap<String,Object> objMap, String id, String name){ 
     this.objMap = objMap; 
     this.id =id; 
     this.name = name; 
    } 

    @Override 
    public void run() { 
     Object monitor = getMonitor(id); 
     synchronized(monitor){ 
      System.out.println("Thread Entered Critica section is:"+id+" and name is:"+name); 

       try { 
        Thread.sleep(10000); 
       } catch (InterruptedException ex) { 
        Logger.getLogger(MyThread.class.getName()).log(Level.SEVERE, null, ex); 
       } 

      System.out.println("Thread Exiting Critical section is:"+id+" and name is:"+name);  

      } 

    } 

    private Object getMonitor(String id){ 
     if(objMap.contains(id)){ 
      return objMap.get(id); 
     }else{ 
      objMap.put(id,new Object()); 
      return objMap.get(id); 
     } 
    } 

} 

Im Folgenden finden Sie Ausgabe:

Thread Entered Critica section is:1 and name is:T1 
Thread Entered Critica section is:1 and name is:T2 
Thread Exiting Critical section is:1 and name is:T1 
Thread Exiting Critical section is:1 and name is:T2 

scheint beide Threads tritt auch wenn Monitor geändert wird.

Jede Hilfe ist willkommen ..

+2

Monitor nur Blöcke wenn es genau dasselbe Objekt zwischen Threads ist, haben Sie zwei Threads und zwei Monitore, es gibt nichts, das sich gegenseitig blockiert –

+0

Worüber sind Sie überrascht? Wie denken Sie, dass Monitore funktionieren? – shmosel

+0

Meine schlechte .. einige Tippfehler in Code .. änderte es .. jetzt zwei Threads .. ein Monitor .. immer noch beide Threads tritt in kritischen Abschnitt – LoneWolf

Antwort

0

Problem ist mit Ihrer getMonitor Methode. Das Ändern hat folgendes Problem.

private Object getMonitor(String id){ 
    objMap.putIfAbsent(id, new Object()); 
    return objMap.get(id); 
} 

Der Grund dafür ist, dass Ihre ursprüngliche getMonitor Methode für Race Condition Probleme anfällig ist. Das häufige Missverständnis ist, dass die Verwendung von Thread Safe-Sammlungen wie Vector, ConcurrentHashMap den Code Thread Thread sicher macht, aber nicht.

Ihre getMonitor hat einen klassischen Check-Then-Act-Codierungsstil (falls sonst) und Ihre objMap ist als statische Variable definiert, so dass alle Threads auf dieselbe Instanz zugreifen.

Mit den Änderungen, die ich vorgeschlagen (objMap.putIfAbsent) die Race-Bedingung vermieden werden kann, da Check-Then-Act wird nun in der Sicherheit des Verriegelungsmechanismus von objMap

Die Änderung erfolgen druckt die folgenden

Thread Entered Critica section is:1 and name is:T1 
Thread Exiting Critical section is:1 and name is:T1 
Thread Entered Critica section is:1 and name is:T2 
Thread Exiting Critical section is:1 and name is:T2 
1

Wie ich in meinem Kommentar erwähnte, ist Ihre getMonitor Methode eine große Wettlaufbedingung, weil Sie nicht auf dem Kartenobjekt synchronisieren, also zwischen der Zeit, die Sie überprüfen, ob der Schlüssel existiert und der Zeit, in der Sie ein neues Objekt einfügen, der andere Thread kann das gleiche tun.

Da Sie jedoch eine Sekunde warten, bevor Sie den zweiten Thread starten, ist das hier nicht das Problem.

Es Problem ist, dass Sie die ConcurrentHashMap.contains(Object) Methode verwenden, die überprüft, ob der Wert vorhanden ist, nicht, wenn die Schlüssel existieren wie Sie wollen. Sie müssen die Methode ändern: Auch

private Object getMonitor(String id){ 
    synchronized (objMap) { 
     if (objMap.containsKey(id)) { // <---- containsKey(...), not contains(...) 
      return objMap.get(id); 
     } else { 
      objMap.put(id, new Object()); 
      return objMap.get(id); 
     } 
    } 
} 

Sie Ihre falsche Schlussfolgerung, dass Ihr Monitor hätte vermieden wurde überprüft, indem tatsächlich zweimal von anderen Thread gesperrt, welcher Monitor Sie gesperrt

System.out.println(
    "Thread Entered Critica section is:" + id + " and name is:" 
    + name + " and monitor is: " + monitor); 
Verwandte Themen