哪个更有效,为什么?

时间:2010-11-10 15:48:56

标签: java multithreading concurrency

在以下两个同步策略中,哪一个被优化(如在处理和生成的字节代码中)以及应该使用其中一个的场景。

public synchronized void addName(String name) 
{
       lastName = name;
       nameCount++;
       nameList.add(name);
}

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
        nameList.add(name);
    }

}

还有什么是处理并发的可行方法:

  1. 使用java.util.concurrent
  2. 使用上述低级方法
  3. 使用JobUIJob API(如果在eclipse PDE环境中工作)
  4. 由于

6 个答案:

答案 0 :(得分:5)

  • 您更新的两段代码在语义上是相同的。但是,使用第二部分中的同步块可以让您更好地控制,因为您可以在不同的对象上进行同步,或者实际上不会同步不需要的方法部分。
  • 使用java.util.concurrent非常适合尽可能使用同步原语,因为它允许您在更高的抽象级别工作,并使用由技术娴熟的人员编写并进行密集测试的代码。
  • 如果你在eclipse PDE中工作,那么使用它的API很可能是首选的,因为它与平台的其他部分有关。

答案 1 :(得分:5)

  

哪一个被优化(如处理和生成的字节代码)

根据this IBM DeveloperWorks Article Section 1,与同步块相比, synchronized方法生成的字节码更少。这篇文章解释了原因。

文章摘录:

  

当JVM执行synchronized方法时,执行线程识别方法的method_info结构设置了ACC_SYNCHRONIZED标志,然后它自动获取对象的锁,调用方法并释放锁。如果发生异常,线程会自动释放锁。

     

同步方法块   另一方面,绕过了JVM   内置支持获取   对象的锁定和异常处理   并要求功能   用字节代码明确写出来。如果   你读取方法的字节代码   有了同步块,你会的   再看十几个   管理这个的操作   功能。清单1显示了调用   生成两个同步方法   和一个同步块:

已编辑以解决第一条评论

为了给其他SOers提供信用,这里有一个很好的讨论为什么会使用同步。块。如果您搜索一下,我相信您可以找到更有趣的讨论:)

Is there an advantage to use a Synchronized Method instead of a Synchronized Block?

我个人不必使用同步。阻止锁定除this以外的另一个对象,但这是SOERS指出的关于同步的一个用法。块。

答案 2 :(得分:2)

从任何效率的角度来看,这都无关紧要。

拥有阻止的重点是你可以指定自己的锁。您可以选择封装在对象中的锁,而不是使用this,结果是您可以更好地控制谁可以获取锁(因为您可以从对象外部无法访问该锁)。

如果您使用this作为锁定(无论是对方法进行同步还是使用块),程序中的任何内容都可以获取对象的锁定,并且更难以推断出您的程序是在做。

限制对锁的访问会带来可判断性的巨大好处,拥有这种确定性比在某处削减字节码更有利。

答案 3 :(得分:1)

我知道这可能是一个例子,但如果你打算编写这样的代码 - 请再想一想。

对我而言,您似乎在复制信息,除非您发现需要对代码进行性能更改,否则不应该这样做。 (你几乎不应该这样做。)

  • 如果你真的需要这个是在多个线程中运行的代码,我会使用Collections.synchronizedList将nameList变为同步列表。
  • 姓氏应该是一个getter,它可以选择列表中的最后一个元素。
  • nameCount应该是列表的大小。

如果你像现在这样做了,你还必须同步访问引用变量的所有地方,这将使代码的可读性和可维护性更低。

答案 4 :(得分:1)

您可以删除所有锁定:

class Names {
  AtomicReference<Node> names = new AtomicReference<Node>();

  public void addName(final String name) {
    Node old = names.get();
    while (!names.compareAndSet(old, new Node(old, name))) {
      old = names.get();
    }
  }

  public String getName() {
    final Node node = names.get();
    return (node == null) ? null : node.name;
  }

  static class Node {
    final Node parent;
    final String name;

    Node(final Node parent, final String name) {
      this.parent = parent;
      this.name = name;
    }

    int count() {
      int count = 0;
      Node p = parent;
      while (p != null) {
        count++;
        p = p.parent;
      }
      return count;
    }
  }
}

这基本上是Treiber堆栈实现。您可以获取大小,当前名称,并且可以轻松地在内容上实现迭代器(尽管与示例中的迭代器相反)。根据您的需要,也可以使用备用的写时复制容器。

答案 5 :(得分:0)

不可能说,因为这两个代码片段不相同。

差异(对add的调用缺乏同步)可能很重要,可能不是。从你给我们的东西中不可能说出来。

相关问题