2017-01-04 5 views
0

注:以下scenarioisが有効でないにもかかわらず同期ブロックの概念に違反し、まだ私はそう2つのスレッド

は二つのスレッドを作成した場合、それがどのように動作するかを知ってみました、両方のスレッドが同じクリティカルセクションを実行しようとすると、驚くことに両方のスレッドがモニタを変更してもクリティカルセクションに入ります。

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 

は、両方のスレッドがモニターを変更しても入るようだ:以下

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); 
     } 
    } 

} 

が出力されます。

どれヘルプは高く評価され..

+2

ブロックのみを監視スレッド間にまったく同じオブジェクトがあれば、2つのスレッドと2つのモニタがあり、互いにブロッキングするものはありません –

+0

あなたは何について驚いていますか?モニターはどのように機能すると思いますか? – shmosel

+0

私の悪い..コードのいくつかのタイプミス..変更されました..現在2つのスレッド.. 1つのモニター..まだ両方のスレッドがクリティカルセクションに入る – LoneWolf

答えて

0

問題は、あなたのgetMonitor方法です。それを変更すると次の問題が修正されます。

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

の理由は、あなたの元getMonitor方法は、レースコンディションの問題のための傾向があるということです。よくある誤解は、Vector,ConcurrentHashMapのようなスレッドセーフのコレクションを使用すると、本質的にあなたのコードをスレッドセーフにしますが、それはできません。

getMonitorには古典的なチェック・アンド・アクト・アクト・スタイルのコーディングがあり(その他の場合)、objMapはすべてのスレッドが同じインスタンスにアクセスするように静的変数として定義されています。チェックイン後、同法は、今変更は以下の

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 
を印刷し objMap

のロック機構の安全性の内部で行われるため、競合状態を回避することができ、私は提案された変更(objMap.putIfAbsent)で

1

私のコメントで述べたように、あなたのgetMonitorメソッドは大きな競合状態です。なぜなら、キーが存在するかどうかをチェックする時間と新しいオブジェクトを入れる時間との間でマップオブジェクトを同期させないからです。他のスレッドは同じことをすることができます。

しかし、2番目のスレッドを開始する前に1秒待つので、ここで問題にはなりません。

あり問題は、あなたが望むようにキーが存在しない場合は、が存在するかどうかをチェックするConcurrentHashMap.contains(Object)方法を、使用していることです。あなたがする方法を変更する必要があります。また

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); 
     } 
    } 
} 

、あなたのモニタが実際にあなたがロックされて監視されチェックすることにより、別のスレッドによって2回ロックされたあなたの間違った結論を避けることができた:

System.out.println(
    "Thread Entered Critica section is:" + id + " and name is:" 
    + name + " and monitor is: " + monitor); 
関連する問題