Java同步和方面的性能
我刚刚意识到我需要在一个方面同步大量的数据收集代码,但性能是一个真正的问题。如果性能下降太多,我的工具将被扔掉。我将分别编写int和long以及各种数组、数组列表和映射。一个应用程序将有多个线程进行函数调用,这些调用将由我的方面接收。我应该注意哪些会对绩效产生负面影响的事情?哪些代码模式更有效 特别是,我有一个方法调用许多其他数据记录方法:Java同步和方面的性能,java,performance,synchronization,aspectj,Java,Performance,Synchronization,Aspectj,我刚刚意识到我需要在一个方面同步大量的数据收集代码,但性能是一个真正的问题。如果性能下降太多,我的工具将被扔掉。我将分别编写int和long以及各种数组、数组列表和映射。一个应用程序将有多个线程进行函数调用,这些调用将由我的方面接收。我应该注意哪些会对绩效产生负面影响的事情?哪些代码模式更有效 特别是,我有一个方法调用许多其他数据记录方法: void foo() { bar(); woz(); ... } 这些方法主要是增加方面字段的增量 void bar() {
void foo() {
bar();
woz();
...
}
这些方法主要是增加方面字段的增量
void bar() {
f++; // f is a field of the aspect
for (int i = 0; i < ary.length; i++) {
// get some values from aspect point cut
if (some condiction) {
ary[i] += someValue; // ary a field of the aspect
}
}
}
(见下文),或方法中的单个数据元素:
ArrayList<Integer> a = new ArrayList<Integer>();
void bar() {
synchronize(a) {
// synchronized code
}
}
ArrayList a=新的ArrayList();
空条({
同步(a){
//同步代码
}
}
并发性非常棘手。很容易出错,但很难做到正确。在这一点上,我不会太担心性能。我最关心的是让并发代码安全地工作(没有死锁或竞争条件)
但在绩效问题上:如果有疑问,请提供个人资料。很难说不同的同步方案会如何影响性能。我们更难给你提建议。我们需要更多地了解您的代码,更深入地了解应用程序的功能,以便为您提供真正有用的答案。相比之下,分析为您提供了一种方法是否比另一种方法慢的确凿证据。它甚至可以帮助你确定经济放缓的原因
现在有很多很棒的Java评测工具。Netbeans和Eclipse分析器很好
此外,我建议您完全不要使用原始同步。尝试使用java.util.concurrency
包中的一些类。它们使编写并发代码变得更容易,并且更不容易出错
另外,我建议您阅读Brian Goetz等人的文章。这篇文章写得很好,涵盖了很多领域。Upadte:写了下面的文章后,我发现您稍微更新了这个问题。请原谅我的无知——我不知道什么是“方面”——但是从您发布的示例代码中,您也可以考虑使用原子/并发集合(例如AtomicInteger、AtomicIntegerArray)或。不过,这可能意味着您的代码需要重新分解。(在双进程超线程Xeon上的Java 5中,明显优于同步阵列;抱歉,我还没有时间在更多进程/更高版本的JVM上重复测试——请注意,“同步”的性能从那时起有所提高。) 如果没有关于您的特定计划的更具体的信息或指标,您所能做的就是遵循良好的计划设计。值得注意的是,JVM中同步锁的性能和优化在过去几年中一直是研究和关注最多的领域之一(如果不是的话)。所以在最新版本的JVM中,它并没有那么糟糕 所以一般来说,我会说在不“发疯”的情况下进行最小程度的同步。我所说的“最低限度”是指你尽可能少地使用锁,只有需要使用特定锁的部分才使用特定锁。但前提是更改很容易,并且很容易证明您的程序仍然正确。例如,不要这样做:
synchronized (a) {
doSomethingWith(a);
longMethodNothingToDoWithA();
doSomethingWith(a);
}
当且仅当您的程序仍然正确时,才考虑执行此操作:
synchronized (a) {
doSomethingWith(a);
}
longMethodNothingToDoWithA();
synchronized (a) {
doSomethingWith(a);
}
但是请记住,使用不必要的锁进行奇怪的简单字段更新可能不会产生太大的实际影响,实际上可以提高性能。有时候,长时间持有一把锁,少做一些锁的“整理”工作是有益的。但是JVM可以做出一些这样的决定,所以你不必过于偏执——只要做一些一般明智的事情,你就会没事了
通常,尝试为每一组方法/访问设置一个单独的锁,这些方法/访问共同构成一个“独立进程”。除此之外,拥有一个单独的lock对象可能是将锁封装在它所使用的类中的一种好方法(即防止外部调用方以您无法预测的方式使用它),但是将一个对象用作另一个对象本身可能没有性能差异(例如,使用实例本身而不是像您建议的那样声明为该类中的锁的私有对象),前提是这两个对象将以完全相同的方式使用。如果您将方面编译到应用程序中,那么如果您在运行时(加载类型编织)这样做,基本上不会对性能造成影响然后你会看到一个性能的打击 如果每个方面都是同步的,那么它可能会减少同步的需要 您应该在尽可能短的时间内尽可能少地进行同步,以减少任何问题 如果可能,您可能希望在线程之间共享尽可能少的状态,保持尽可能多的本地状态,以减少死锁问题
更多信息将导致更好的答案。顺便说一句:)经验法则是不要在
上同步此
-大多数情况下,这是一个性能问题-所有方法都在一个对象上同步
考虑使用锁-它们是一个非常好的抽象和许多优良的特性,例如,尝试锁定一段时间,然后放弃:
if(commandsLock.tryLock(100, TimeUnit.MILLISECONDS)){
try {
//Do something
}finally{
commandsLock.unlock();
}
}else{
//couldnt acquire lock for 100 ms
}
我对使用java.util.concurrent
有第二种看法。我会进行两级同步
- 同步集合访问(如果需要)
- 同步字段访问
if(commandsLock.tryLock(100, TimeUnit.MILLISECONDS)){
try {
//Do something
}finally{
commandsLock.unlock();
}
}else{
//couldnt acquire lock for 100 ms
}
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
}
}
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
}
}
}
Integer foo = ary.get(ii);
synchronized(foo){
foo++;
}