2013-11-29 4 views
6

У меня есть синхронизированный метод, который появляется, чтобы «использовать» синхронизацию значительно дольше, чем следовало бы. Это выглядит примерно так:Java синхронизированный метод с дорогостоящими параметрами

public static synchronized void myMethod(MyParameter p) { 
    //body (not expensive) 
} 

Звонок выглядит;

myMethod(generateParameter()); 

Где generateParameter(), как известно, очень дорого (занимает много времени) вызова. Мое мышление заключается в том, что мьютекс в классе myMethod заблокирован во время выполнения generateParameter(), что происходит? Я нахожу, что это другая проблема для отладки, но это то, что, похоже, происходит.

+0

ли 'generateParameter' также синхронизированы на уровне метода? –

+1

Для правильного ответа требуется код для 'generateParameter'. –

+1

'generateParameter()' не синхронизирован и существует как статический метод в противном случае не связанный с ним класс. – lynks

ответ

5

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

Занимает ли оно длительное время, или оно бесконечно заблокировано? (в тупике)

+0

Я был на 99% уверен, что именно так работают параметры метода, но это просто похоже на объяснение. Спасибо, мне нужно будет профилировать его должным образом. – lynks

+0

Итак, когда вы говорите, что синхронизация занимает больше времени, чем нужно, вы имеете в виду, что в ожидании «getParameter()» это займет еще больше времени? Может быть, вы должны попытаться понять, к чему это дополнительное время. Мне было бы любопытно, что получилось, поэтому вы можете обновить нас все позже :) – Miquel

+0

Все остальные потоки блокируют ожидание этой блокировки в течение нескольких секунд, а тело 'myMethod()' известно быть дешевым (~ <10 мс). Я уверен, что есть разумное объяснение, у меня был момент, когда я задавался вопросом, когда будет приобретен замок. – lynks

5

Нет, это не так.

Метод generateParameter выполнен до звонка до myMethod.

В Java все аргументы метода всегда оцениваются перед вызовом метода.

specification of method call подробно объясняет это (спасибо Виктору Сорокину).

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

Ваш код такой же, как показано ниже, за исключением новой переменной:

MyParameter p = generateParameter(); 
myMethod(p); 
+1

В Java все аргументы метода всегда оцениваются до вызова метода: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.4 –

2

Нить выполнения myMethod входит монитор объекта в начале метода и держит его, пока он не выйдет. Любые операции, выполняемые внутри метода, равны synchronized, но все параметры вызова оцениваются до вызова, поэтому generateParameter не выполняется внутри окна блокировки myMethod.

Если generateParameter имеет любую синхронизацию на нем, он может конкурировать за одну и ту же блокировку, поскольку без явного объекта синхронизации JVM синхронизируется с объектом, метод которого вызывается.

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

0

«мьютекс на классе MyMethod блокируется во время выполнения generateParameter()»

Насколько я знаю, что замок приобретается не до выполнения функции generateParameter заканчивается.

1

Вместо static synchronized void myMethod(p) его лучше использовать ReadWriteLock для ваших ресурсов:

MyParameter p = generateParameter(); 

myMethod(p){ 

    ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 


    readWriteLock.readLock().lock(); 

    // multiple readers can enter this section 
    // if not locked for writing, and not writers waiting 
    // to lock for writing. 

    readWriteLock.readLock().unlock(); 


    readWriteLock.writeLock().lock(); 

    // only one writer can enter this section, 
    // and only if no threads are currently reading. 

    readWriteLock.writeLock().unlock(); 
} 
+0

Спасибо за это, Я обычно использую синхронно либерально и часто пропускаю другие инструменты параллелизма. – lynks

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