【问题标题】:Synchronization, When to or not to use?同步,何时使用或不使用?
【发布时间】:2012-05-21 19:42:54
【问题描述】:

我已经开始学习 Java 中的并发和线程。我知道同步的基础知识(即它的作用)。从概念上讲,我理解它提供了对具有 Java 中的多个线程的共享资源的互斥访问。但是当面对像下面这样的例子时,我很困惑让它同步是否是一个好主意。我知道代码的关键部分应该同步,这个关键字不应该被过度使用,否则会影响性能。

public static synchronized List<AClass> sortA(AClass[] aArray) 
{
    List<AClass> aObj = getList(aArray);

    Collections.sort(aObj, new AComparator());

    return aObj;
}

public static synchronized List<AClass> getList(AClass[] anArray) 
{
    //It converts an array to a list and returns
}

【问题讨论】:

  • 不需要同步,因为你的方法看起来是无状态的。

标签: java synchronized


【解决方案1】:

您的静态方法不依赖于任何共享状态,因此不需要同步。

【讨论】:

    【解决方案2】:

    假设每个线程传递不同的数组,则不需要同步,因为其余变量都是本地的。

    如果您触发几个线程都调用sortA 并传递对同一数组的引用,如果没有synchronized,您将遇到麻烦,因为它们会相互干扰。

    请注意,从示例中可以看出getList 方法从一个数组返回一个新的List,这样即使线程传递相同的数组,您也会得到不同的List 对象。这是误导。例如,使用 Arrays.asList 创建一个由给定数组支持的 List,但 javadoc 明确指出 Changes to the returned list "write through" to the array. 所以要小心这一点。

    【讨论】:

      【解决方案3】:

      没有定义什么时候使用同步的规则,什么时候不使用,当你确定你的代码不会被并发线程访问时,你可以避免使用同步。

      【讨论】:

        【解决方案4】:

        您正确理解的同步会影响应用程序的吞吐量,并且还可能导致线程不足。

        所有 get 基本上应该是非阻塞的,因为并发包下的 Collections 已经实现。

        在您的示例中,所有调用线程都将传递自己的数组副本,getList 不需要同步,sortA 方法也是如此,因为所有其他变量都是本地的。

        局部变量存在于堆栈中,每个线程都有自己的堆栈,因此其他线程无法干扰它。

        当你改变对象的状态时你需要同步,而其他线程应该在一致的状态下看到,如果你的调用没有改变你不需要同步的对象的状态。

        【讨论】:

          【解决方案5】:

          当您在多个调用之间共享数据时通常需要同步,并且可能会修改数据导致不一致。如果数据是只读的,则不需要同步。

          在上面的代码 sn-p 中,没有共享数据。这些方法对提供的输入起作用并返回输出。如果多个线程调用您的方法之一,则每个调用都有自己的输入和输出。因此,任何地方都不存在不一致的可能性。因此,您在上述 sn-p 中的方法不需要同步。

          如果不必要地使用同步,由于所涉及的开销,肯定会降低性能,因此只有在需要时才应谨慎使用。

          【讨论】:

          • 你怎么知道没有数据被共享?线程可以将相同的数组传递给sortA 方法。
          • 很有可能!好吧,在这种情况下,您肯定需要同步。关键是代码的用户应该知道你的代码是否是线程安全的。作为开发人员,您知道您的代码是否应该是线程安全的。如果没有,那么您需要为用户记录它,以便他们可以在有趣的场景中显式同步。您无需同步代码中的所有内容。
          • 在上面的 sn-p 中为它提供的功能同步一个静态方法是不正确的。用户应在需要时防范您在外部提到的场景。
          【解决方案6】:

          我不会在单线程代码上使用synchronized。即,多个线程不可能访问一个对象。

          这可能看起来很明显,但是 JDK 中使用的大约 99% 的 StringBuffer 只能由一个线程使用,可以替换为 StringBuilder(不同步)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-27
            • 2021-02-18
            • 1970-01-01
            相关资源
            最近更新 更多