2013-09-09 2 views
1

Существует какая-то странная вещь. Когда я вхожу в синхронизированный блок, я пытаюсь напечатать имя Thread.After заявления печати, я делаю паузу паузы в 100000 секунд.Как два потока могут одновременно войти в синхронизированный блок?

@Override 
public int getNextAvailableVm() { 
    synchronized(this) { 

     System.out.println(Thread.currentThread().getName()); 

     try {Thread.sleep(100000000);}catch(Exception exc){} 

     String dataCenter = dcc.getDataCenterName(); 
     int totalVMs = Temp_Algo_Static_Var.vmCountMap.get(dataCenter); 
     AlgoHelper ah = (AlgoHelper)Temp_Algo_Static_Var.map.get(dataCenter); 
     . 
     . 
     . 
    } 
} 

Но по мере того как этот метод запущен, выдается имя из 2 потоков.

Thread-11 
Thread-13 

, и после этого происходит длительная пауза. Почему это ? Как два потока могут войти в синхронизированный блок, когда первый поток еще не покинул блок?

+11

Вы действительно вызываете 'getNextAvailableVm()' на том же самом объекте? – rocketboy

+5

Вы уверены, что ваш сон не прерывается? (напечатать что-нибудь в блоке исключений) – njzk2

+0

@ njzk2 ничего не печатается из блока исключений –

ответ

3

Если два потока работают против одного и того же объекта, тогда этого не должно произойти.

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

Если вы хотите использовать несколько объектов, то вы должны не использования synchronized(this), вы должны создать static final Object к synchronize на. Пожалуйста, не синхронизируйте по this.getClass(), так как это ломается.

+0

Как происходит синхронизация на этом.getClass()? И верно ли это также для синхронизации в ClassName.class? –

+1

@JensSchauder - Если вы синхронизируете на 'this.getClass', то ** все ** объекты этого типа будут блокироваться, когда ** любые ** из них синхронизируются. Также подкласс вашего объекта будет неправильно синхронизироваться с объектами суперкласса. Это почти наверняка не то, что вы хотите. – OldCurmudgeon

0

Скорее всего вы вызываете getNextAvailableVm() в разных экземплярах содержащего класса. Поскольку вы синхронизируетесь на this, вы будете блокировать на двух разных мониторах (первые блокировки потока на экземпляре1, второй на экземпляре2).

Есть много способов, вы можете исправить это:

  • сделать весь метод synchronized
  • синхронизировать this.getClass()
  • определить статический объект, чтобы зафиксировать на
  • используют методы из Java. util.concurrent.locks делать блокировку

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

+0

Не синхронизируйте функцию 'getClass()'. Это сломается, если вы начнете включать подклассы. – Keppil

0

Я думаю, ниже прог, будет работать, как вы ожидали,

Locked на Thread1.Class, две нити не будут выполняться метод одновременно

public class Test { 
    public static void main(String [] args) { 
     Thread1 t1 = new Thread1(); 
     Thread1 t2 = new Thread1(); 
     t1.start(); 
     t2.start(); 
    } 
} 

class Thread1 extends Thread{ 
    public void run(){ 
     getNextAvailableVm(); 
    } 
    public void getNextAvailableVm() { 
     synchronized(Thread1.class) { 
      System.out.println(Thread.currentThread().getName()); 
      try { 
       Thread.sleep(1000); 
       }catch(Exception exc){} 
      System.out.println(Thread.currentThread().getName()); 
     } 

    } 
} 

ВЫВОД Thread-1 Thread-1 Thread-0 Thread-0