代码之家  ›  专栏  ›  技术社区  ›  core

使您的收藏线程安全?

  •  9
  • core  · 技术社区  · 16 年前

    在设计集合类时,是否有任何理由不私下实现锁以使其线程安全?或者我应该把责任留给收藏品的消费者?

    17 回复  |  直到 13 年前
        1
  •  13
  •   Orion Edwards    16 年前

    有没有什么理由不私下实现锁以保证线程安全?

    这要看情况而定。您的目标是编写一个由多个线程访问的集合类吗? 如果是这样,请确保它的线程安全。如果没有,不要浪费时间。当人们谈论“过早的优化”时,就是指这种情况。

    解决你的问题。不要试图去解决那些你认为你可能在未来几年会遇到的未来问题,因为你看不到未来,你总是错的。

    注意:您仍然需要以可维护的方式编写代码,这样如果您 需要一起为集合添加锁定,这不会非常困难。我的观点是“不要实现你不需要也不会使用的功能”

        2
  •  10
  •   flicken    16 年前

    对于Java,应该为速度保持不同步。该系列的消费者可以将 synchronization wrapper 如果需要的话。

        3
  •  6
  •   Ohad Schneider    14 年前

    线程安全集合可能是骗人的。Jared Par发表了一些关于线程安全集合的有趣文章:

    问题是有几个 线程安全集合的级别。我 当大多数人说线的时候 安全收集它们的真正含义 _ 修改和访问时损坏 从多线程__

    但是如果构建一个安全的数据线程 列表是如此简单,为什么微软 将这些标准集合添加到 框架?

    答:线程安全列表是一个 实际上无法使用类,因为 设计引领你走向坏的道路 代码。

    这个设计的缺陷不是 很明显,直到你检查如何列表 是常用的。例如,取 以下代码试图 从列表中提取第一个元素 如果有的话。

    static int GetFirstOrDefault(ThreadSafeList<int> list) {
        if (list.Count > 0) {
            return list[0];
        }
        return 0; }
    

    这是一个典型的比赛条件。考虑列表中只有一个>元素的情况。如果另一个线程删除了if语句和返回语句之间的元素,则返回语句将引发异常,因为它试图访问列表中的无效索引。尽管threadsafeList是数据线程安全的,但是没有任何东西可以保证对同一对象的下一次调用中一个调用的返回值的有效性。

    http://blogs.msdn.com/b/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx

    http://blogs.msdn.com/b/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

        4
  •  3
  •   Quibblesome    16 年前

    集合类需要尽可能快。因此,把锁打开。

    调用代码将知道锁的最佳位置集合类不知道。在最坏的情况下,应用程序将不得不添加一个额外的锁,这意味着发生了两个锁,使性能提高了一倍。

        5
  •  2
  •   Daniel A. White    16 年前

    我个人会把它留给消费者。它将使集合类更通用。

        6
  •  2
  •   Chris J    16 年前

    只需在文档中明确指出,您没有使其线程安全,并将其排除在外;或者,对于您的应用程序,如果您希望它线程安全,请使其线程安全,并在文档中注意这一点。唯一的规则是记录它。除此之外,让你的班级为你,如果其他人想使用它,他们可以。

        7
  •  2
  •   Steven M. Cherry    16 年前

    如果我正在寻找一个集合类,并且我需要线程安全功能,而您的类没有这些功能,那么我将立即跳到下一个提供程序,看看它们提供了什么。你的收藏再也不能引起我的注意了。

    请注意开头的“if”。有些客户会想要,有些不会,有些不会在意。如果你打算为消费者建立一个工具包,那为什么不提供这两种产品呢?这样我就可以选择使用哪一个了,但是如果我想要线程安全,你仍然有我的注意力,我不必自己写。

        8
  •  1
  •   Jurney    16 年前

    不保证线程安全的主要原因是性能。线程安全代码可能比非安全代码慢100秒,因此如果您的客户机不想要这个特性,这是一个很大的浪费。

        9
  •  1
  •   Lasse V. Karlsen    16 年前

    请注意,如果您试图使任何类线程安全,则需要决定常见的使用场景。

    例如,在集合的情况下,仅使所有属性和方法单独线程安全可能不足以满足使用者的需求,因为如果在读取后计数发生变化,那么首先读取计数,然后循环或类似操作将不会有太大的好处。

        10
  •  1
  •   MetroidFan2002    16 年前

    制作集合线程安全是杀死Java的向量和哈希表类的原因。与每次访问类时进行同步命中相比,客户端更容易用线程安全包装器包装(如前所述),或者在方法子集上同步数据访问。几乎没有人使用vector或hashtable,如果使用,他们会被嘲笑,因为他们的替换(arraylist和hashmap)会更快。这是不幸的,因为我(来自C++背景)更喜欢“向量”名称(STL),但ArrayList是留在这里。

        11
  •  1
  •   tzot    16 年前

    基本上,将集合设计为线程安全的,在类的两个方法中实现锁:lock()和unlock()。在需要的地方给他们打电话,但不要让他们空手。然后将集合的子类化,实现lock()和unlock()方法。两个班一个价。

        12
  •  1
  •   Alex Miller    16 年前

    不使集合线程安全的一个很好的原因是提高了单线程性能。示例:arraylist over vector。将线程安全延迟到调用方允许未同步的用例通过避免锁定进行优化。

    使集合线程安全的一个很好的原因是提高了多线程性能。示例:HashMap上的ConcurrentHashMap。由于chm内部化了多线程问题,因此它可以分条锁定,从而比外部同步更有效地实现更大的并发访问。

        13
  •  0
  •   Morten Christiansen    16 年前

    这将使您无法同时从多个线程访问集合,即使您知道您接触的元素没有被其他任何人使用。

    例如,具有基于整数的索引访问器的集合。每个线程可能从其ID知道可以访问哪些索引值,而不必担心脏的读/写。

    另一种情况是,当数据只从集合中读取而不写入时,您将获得不必要的性能影响。

        14
  •  0
  •   Michael Bobick    16 年前

    我同意由消费者决定是正确的做法。对于集合实例是在上同步还是在上同步其他对象,if为使用者提供了更大的灵活性。例如,如果您有两个需要更新的列表,那么使用一个锁将它们保存在一个同步块中可能是有意义的。

        15
  •  0
  •   extraneon    16 年前

    如果您使集合类成为线程安全类,则不要使其成为线程安全类。很难做对(例如正确和快速),而且当你做错了的时候,你的消费者的问题(heisenbugs)很难调试。

    相反,实现一个集合API并使用Collections.SynchronizedCollection(YourCollectionInstance)在需要时获取线程安全的实现。

    只需参考类javadoc中相应的collections.synchronizedxxx方法;它将清楚地表明您在设计中考虑了线程安全性,并确保使用者可以使用线程安全选项。

        16
  •  0
  •   Brian Rudolph    16 年前

    这是一个好的开始。

    thread-safe-dictionary

    但是您会注意到您丢失了集合的一个重要特性——枚举。您不能对枚举器进行线程安全保护,除非您实现自己的枚举器,该枚举器将实例锁保留回集合本身,否则它实际上是不可行的。我怀疑这会导致主要的瓶颈和潜在的僵局。

        17
  •  0
  •   Jeremy    13 年前

    从JDK5开始,如果您需要一个线程安全的集合,我将首先查看java.util.concurrent中已经实现的集合之一是否可以工作。作为 实践中的Java并发 指出(包括编写大多数类的人)正确地实现这些是非常困难的,特别是在性能很重要的情况下。

    引用 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html

    并发集合

    除了排队,这个包裹还提供 设计的集合实现 用于多线程上下文: 当前地图, 同时发生Kiplistmap, 当前的kiplistset, CopyOnWriteArrayList,和 CopyOnWriteArraySet。多线程时 期望访问给定的 集合,ConcurrentHashMap是 通常优于同步 hashmap和concurrentskiplistmap 通常比 同步树映射。一 CopyOnWriteArrayList优于 同步数组列表 预期读取次数和 遍历数大大超过 列表的更新数。