2013-03-11 2 views
12

Вот часть текста, которую я нашел по ссылке this.Java - синхронизация статических методов

«Избегайте блокировки статических методов

Худшим решения поставить„синхронизированные“ключевые слова на статических методах, что означает, что он будет блокировать на все экземпляры этого класса.»

Почему синхронизация статического метода блокирует все экземпляры класса? Разве он не должен просто блокировать класс?

+7

Поскольку статические методы доступны для всех экземпляров, он блокирует все экземпляры. – duffymo

+0

Хотя статические методы доступны экземплярам, ​​к ним не следует обращаться через экземпляры. Они должны быть доступны только статически. Так что автор говорит, что это неправильно. – sotn

+1

@duffymo Нет, он не блокирует * любые * экземпляры. «synchronized (this)» будет действовать во время этой блокировки. – EJP

ответ

6

Вот мой тестовый код, который показывает, что вы правы, и эту статья немного осторожничать:

class Y { 
    static synchronized void staticSleep() { 
     System.out.println("Start static sleep"); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
     } 
     System.out.println("End static sleep"); 
    } 

    synchronized void instanceSleep() { 
     System.out.println("Start instance sleep"); 
     try { 
      Thread.sleep(200); 
     } catch (InterruptedException e) { 
     } 
     System.out.println("End instance sleep"); 
    } 
} 

public class X { 
    public static void main(String[] args) { 
     for (int i = 0; i < 2; ++i) { 
      new Thread(new Runnable() { 

       public void run() { 
        Y.staticSleep(); 
       } 
      }).start(); 
     } 

     for (int i = 0; i < 10; ++i) { 
      new Thread(new Runnable() { 

       public void run() { 
        new Y().instanceSleep(); 
       } 
      }).start(); 
     } 
    } 
} 

гравюры:

Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start static sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End static sleep 
Start static sleep 
End static sleep 

Так static synchronized не имеет никакого отношения к synchronized методов в случаях ...

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

+1

Спасибо за тестовый код! Даже чрезмерная осторожность не должна делать то, что автор говорит правильно. Блокировки экземпляров и классов являются отдельными. В статье я сомневался в освященном SCJP, тем более что автор, по его резюме, является экспертом. – sotn

7

Собственно замок на статический метод класса Foo, то же самое, поставив замок на Foo.class (который является единственным экземпляром):

public static void doSomething() 
{ 
    synchronized(Foo.class) 
    { 
     // ... 
    } 
} 
4

Вы правы — фактическая блокировка на Class сам экземпляр, а не на любой экземпляр класса (не говоря уже о все экземпляров) —, но я думаю, что вы слишком буквально интерпретируете связанную страницу. Он сам использует фразу «статический замок (блокировка класса)», поэтому его автор знает, как работает блокировка. Но если у вас много экземпляров в разных потоках, которые используют синхронные статические методы, тогда эти экземпляры будут блокировать друг друга. Синхронизированные статические методы не будут вызывают блокировку синхронизированного экземпляров методов, но проблема существует независимо.

32

Чтобы понять это, самый простой способ - сравнить, как блокировка работает против метода экземпляра и статического метода. Допустим, у вас есть класс Test.java, который имеет два метода.

public class Test{ 
    public synchronized void instanceMethod(){ 
    } 

    public synchronized static void staticMethod(){ 
    } 
} 

Между тем существуют два экземпляра класса Test, testA и testB. А также есть два потока tA и tB, пытающихся параллельно обращаться к классу Test.

замок на instanceMethod: Когда TĀ получает блокировку на instanceMethod из Testa, Tb не может получить доступ к тому же методу в Testa, однако Tb все еще свободно ссылаться на instanceMethod в testB. Поскольку синхронизация против instanceMethod является уровень экземпляра блокировки

замок на STATICMETHOD: Однако, когда Tā получает блокировку на STATICMETHOD, замок не имеет ничего общего с Testa или testB, так как синхронизация на статический метод является блокировка уровня класса.Это означает, Tb не может получить доступ к STATICMETHOD на всех, пока TĀ не уберет блокировку

+0

Очень хорошее объяснение разницы в механизмах блокировки. – asgs

+1

Наконец-то появилась идея статического синхронизированного метода. Хорошее объяснение. – sonia

+0

Да, это довольно хорошее резюме экземпляра блокировки против статических методов. – JohnMerlino

2

Он не говорит ' заблокировать все экземпляры класса '. Он говорит: «Заблокируйте на все экземпляры класса. Это плохо сформулировано, правда неверно, но это не говорит, что вы сказали, что он сказал.

2

Синхронный метод получает монитор (§17.1) перед его выполнением. Для класса (статического) метода используется монитор, связанный с объектом класса для класса метода. Для метода экземпляра используется связанный с ним монитор (объект, для которого был вызван метод).

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.3.6

Смежные вопросы