Синхронизация Java и производительность в аспекте

У gradle есть несколько способов проверки зависимостей, но я не думаю, что какой-либо из них имеет фильтр, который ограничивает его только «проектными» зависимостями. См. https://docs.gradle.org/current/userguide/userguide_single.html#sec:listing_dependencies

Также обратите внимание, что проект имеет разные конфигурации зависимостей, где каждая конфигурация имеет свой собственный набор зависимостей.

Итак, вам нужно поговорить, например, о показе всех «компилируемых» зависимостей проекта.

Однако одно из больших преимуществ gradle заключается в том, что его легко написать с помощью groovy.

Этот быстрый черновик работает для меня, чтобы показать все зависимости в конфигурации "compile". Просто добавьте его в корневой проект и вызовите «gradlew projectDependencies». Это было протестировано ровно в одном примере проекта (другими словами «в основном не проверено») и не очень гибкое (конфигурация «компилировать» жестко задана). Однако я попытался сделать это понятным, используя явные типы и несколько строк, чтобы вы могли расширить его:

task projectDependencies {
    doLast {
        showProjectDependencies(rootProject, 0)
    }
}

def showProjectDependencies(Project project, int nesting) {
    ConfigurationContainer configurations = project.configurations
    Configuration configuration = configurations.compile
    println " " * (3 * nesting) + project.name
    DomainObjectSet projectDependencies = configuration.dependencies.withType ProjectDependency
    projectDependencies.forEach {
        showProjectDependencies(it.dependencyProject, nesting + 1)
    }
}

5
задан Community 23 May 2017 в 12:08
поделиться

4 ответа

Concurrency is extremely tricky. It's very easy to get it wrong, and very hard to get right. I wouldn't be too terribly worried about performance at this point. My first and foremost concern would be to get the concurrent code to work safely (no deadlocks or race conditions).

But on the issue of performance: when in doubt, profile. It's hard to say just how different synchronization schemes will affect performance. It's even harder for us to give you suggestions. We'd need to see a lot more of your code and gain a much deeper understanding of what the application does to give you a truly useful answer. In contrast, profiling gives you hard evidence as to if one approach is slower than another. It can even help you identify where the slowdown is.

There are a lot of great profiling tools for Java these days. The Netbeans and Eclipse profilers are good.

Also, I'd recommend staying away from raw synchronization altogether. Try using some of the classes in the java.util.concurrency package. They make writing concurrent code much easier, and much less error prone.

Also, I recommend you read Java Concurrency in Practice by Brian Goetz, et al. It's very well written and covers a lot of ground.

9
ответ дан 18 December 2019 в 07:56
поделиться

Rule of thumb is not to synchronize on this - most of the times it is a performance hit - all methods are synchronized on one object.

Consider using locks - they'a very nice abstraction and many fine features like, trying to lock for a time period, and then giving up:

if(commandsLock.tryLock(100, TimeUnit.MILLISECONDS)){
     try { 
         //Do something
     }finally{
          commandsLock.unlock();
     }
}else{
     //couldnt acquire lock for 100 ms
}   

I second opinion on using java.util.concurrent. I'd make two levls of synchronization

  • synchronize collection access (if it is needed)
  • synchronize field access

Collection access

If your collection are read-only ie no elements get removed-inserted (but elements may change) i would say that you should use synchronized collections (but this may be not needed...) and dont synchronize iterations:

Read only:

for (int i = 0; i < ary.length; i++) {
    // get some values from aspect point cut
    if (some condiction) {
        ary += someValue; // ary a field of the aspect
    }
 }

and ary is instance obtained by Collections.synchronizedList.

Read-write

synchronized(ary){
    for (int i = 0; i < ary.length; i++) {
        // get some values from aspect point cut
        if (some condiction) {
            ary += someValue; // ary a field of the aspect
        }
     }
 }

Or use some concurrent collections (like CopyOnWriteArrayList) which is inherentently therad safe.

Main difference is that - in first read-only wersion any number of threads may iterate over this collections, and in second only one at a time may iterate. In both cases only one therad at a time should increment any given field.

Field access

Synchronize incrementations on fields separately from synchronizing iterations.

like:

  Integer foo = ary.get(ii); 
  synchronized(foo){
      foo++;
  }

Get rid of synchronization

  1. Use concurrent collections (from java.util.concurrent - not from `Collections.synchronizedXXX', latter still need synchronizing on traversal).
  2. Use java.util.atomic that enable you to atomically incrememt fields.

Something you should watch:

Java memory model - its a talk that gives very nice understanding on how synchronizations and data aligment in JAVA works.

4
ответ дан 18 December 2019 в 07:56
поделиться

Обновление: после написания нижеприведенного, я вижу, вы немного обновили вопрос. Простите мое незнание - я понятия не имею, что такое «аспект» - но из опубликованного вами образца кода вы также можете рассмотреть возможность использования атомных / параллельных коллекций (например, AtomicInteger, AtomicIntegerArray) или средств обновления атомарных полей , Однако это может означать ре-факторинг вашего кода. (В Java 5 на двухпроцессорном гиперпоточном Xeon пропускная способность AtomicIntegerArray значительно лучше, чем у синхронизированного массива; извините, я еще не успел повторить тест на других процессах / более поздней версии JVM - обратите внимание, что с тех пор производительность 'synchronized' улучшилась.)

Без более конкретной информации или показателей о вашей конкретной программе, лучшее, что вы можете сделать, это просто следовать хорошей программе . Стоит отметить, что производительность и оптимизация синхронизационных блокировок в JVM была одной из областей (если не областью), которая привлекала наибольшее внимание в последние несколько лет. И поэтому в последних версиях JVM все не так уж плохо.

В общем, я бы сказал синхронизировать минимально, не «сходя с ума» . Под «минимально» я имею в виду, чтобы вы держали блокировку как можно меньше времени, и чтобы только те части, которые должны использовать эту конкретную блокировку, использовали эту конкретную блокировку. Но только если изменение легко сделать и легко доказать, что ваша программа по-прежнему верна. Например, вместо этого:

synchronized (a) {
  doSomethingWith(a);
  longMethodNothingToDoWithA();
  doSomethingWith(a);
}

подумайте о том, чтобы сделать это тогда и только тогда, когда ваша программа все еще будет правильной:

synchronized (a) {
  doSomethingWith(a);
}
longMethodNothingToDoWithA();
synchronized (a) {
  doSomethingWith(a);
}

Но помните, странное простое обновление поля с блокировкой, удерживаемой без необходимости, вероятно, не будет иметь большого значения и может на самом деле улучшить производительность. Иногда может быть полезно удерживать блокировку немного дольше и меньше выполнять «уборку». Но JVM может принимать некоторые из этих решений , так что вам не нужно быть слишком параноиком - просто делайте в целом разумные вещи, и все будет в порядке.

В общем, попробуйте создать отдельный lock для каждого набора методов / доступа, которые вместе образуют «независимый процесс». Помимо этого, наличие отдельного объекта блокировки может быть хорошим способом инкапсуляции блокировки внутри класса, которым он используется (т. Е.

3
ответ дан 18 December 2019 в 07:56
поделиться

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

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

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

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

Кстати, больше информации приведет к лучшему ответу. :)

1
ответ дан 18 December 2019 в 07:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: