2017-01-04 3 views
0

Примечание: Даже если ниже scenariois не действительны, нарушающий концепцию синхронизированного блока, до сих пор я пытался узнать, как это работает, если такДве нити в синхронизированный блок, изменяя монитор во времени выполнения

создал две темы, оба потока пытаются выполнить один и тот же критический раздел, причем оба потока входят в критический раздел, даже если сменить монитор.

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

} 

Ниже выводится:

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 

Кажется обе нити входит даже если монитор будет изменен.

Любая помощь приветствуется ..

+2

монитор только блоки если его точно такой же объект между потоками, у вас есть два потока и два монитора, нет ничего блокирующего друг друга –

+0

Что вас удивляет? Как вы думаете, как работают мониторы? – shmosel

+0

My bad .. некоторые опечатки в коде .. изменил его .. сейчас две нити .. один монитор .. все еще обе нити входят в критический раздел – LoneWolf

ответ

0

Проблема с методом getMonitor. В результате изменения в нем будет исправлена ​​проблема.

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

Причина заключается в том, что ваш оригинальный getMonitor метод склонен к вопросам состояния гонки. Распространенное заблуждение состоит в том, что использование коллекций Thread Safe, таких как Vector, ConcurrentHashMap по сути делает ваш код Thread Safe, но это не так.

Ваш getMonitor имеет классический стиль кодирования «Код проверки» (если есть), а ваш objMap определяется как статическая переменная, поэтому все потоки будут обращаться к одному экземпляру.

С изменениями я предложил (objMap.putIfAbsent) условие гонки можно избежать, потому что Check-Then-Act теперь будет сделано в безопасности механизма запирания 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 
1

Как я уже упоминал в своем комментарии, ваш метод getMonitor является большим условием гонки, потому что вы не синхронизируете объект карты так, что между временем, которое вы проверяете, существует ли ключ и время, в которое вы помещаете новый объект, другой поток может сделать то же самое.

Однако, поскольку вы подождали одну секунду до начала второго потока, это не проблема.

There проблема в том, что вы используете 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); 
     } 
    } 
} 

Кроме того, вы могли бы избежать ваш неправильный вывод, что монитор был заблокирован дважды другой поток, фактически проверяя какой монитор вы заперли:

System.out.println(
    "Thread Entered Critica section is:" + id + " and name is:" 
    + name + " and monitor is: " + monitor); 
Смежные вопросы