同步容器并发容器

同步容器类

  • Vector、Hashtable,及由Collections.synchronizedXxx等工程方法创建的类。
  • 这些类实现线程安全方式是:将它们的状态封装起来,并对每个公有方法都进行同步,使得每次只有一个线程能方法容器状态。

同步容器类的问题

  • 客户端新建的复合操作需要通过容器类的锁来保证原子性。
  • 在迭代操作中,多线程情况下回出现ArrayIndexOutOfBoundsException异常,如果要解决,则需要在客户端加锁,但是牺牲了一些伸缩性。

迭代器与CncurrrentModificationException

  • 发现容器在迭代过程中被修改过,会抛出CME异常。实现原理:将容器计数器与容器关联起来:如果在迭代期间计数器被修改,那么hasNext或next将抛出CME异常。然后,这种检查在没有同步的情况下进行的,因此可能看到失效的计数值:ABA问题。

隐藏的迭代器

  • 容器的toString、hashCode、equals、containsAll、removeAll、retainAll以及包容器作为参数的构造函数都会对容器进行迭代,在并发下就可能出现CME异常。所以在并发情况下,在迭代期间需要对容器加锁。

并发容器

  • 并发容器为了改变同步容器的性能,同步容器对容器状态的访问时串行化,以实现线程安全,这种方法降低了并发性,和吞吐量。
  • 并发容器针对多线程并发访问设计的,如果需要提高并发性使用以下替代方案。
  • ConcurrentHashMap代替同步且散列的Map.
  • CopyOnWriteArrayList用于在遍历操作为主要操作的情况下代替同步的List。
  • ConcurrentMap接口中增加了常见复合操作的支持:“若没有则添加”、替换、有条件删除。
  • ConcurrentSkipListMap代替SortedMap
  • ConcurrentSkipListSet代替SortedSet
    *并发容器类提供的迭代器不会抛出CME异常。

Queue、BlockingQueue容器接口

  • Queue用来临时保存一组待处理元素,实现类包括:ConcurrentLinkedQueue(先进先出队列)、PriorityQueue(优先队列,非并发)
  • Queue上的操作不会阻塞,如果队列为空,返回空值。
  • Queue通过LinkedList来实现的。
  • BlockingQueue扩展Queue,增加了可阻塞的插入和获取等操作,如果队列为空,那么获取元素操作将一直阻塞,直到队列中出现一个可用元素。插入时,如果队列已满(对于有界队列来说,无界队列除外),插入操作将一直阻塞,知道队列中出现可用空间。适合“生产者-消费者模式”
  • BlockingQueue提供了offer方法,当队列满时offer添加元素失败返回false,此时可以做相应策略调整(减少生产线程或序列化数据到磁盘),同样也提供了poll方法,在一定时间内如果没有获取到元素则返回null。

ConcurrentHashMap

  • 使用分段锁(Lock Striping)来提高并发性和伸缩性。
  • size和isEmpty返回的结果可能会过期,实际上他只是一个估值,但这两个方法用的不多。
  • 在CHM中没有实现对Map加锁以提供独占方法,在Hashtable、synchronizedMap中获得Map的锁能防止其他线程访问这个Map
  • 与Hashtable、synchronizedMap相比,CHM有更多优势,大多数情况下使用CHM来提高代码的伸缩性,只有当程序需要加锁Map以进行独占访问,或者需要依赖同步Map带来的一些其他作用是才应该放弃CHM.

CopyOnWriteArrayList、CopyOnWriteArraySet

  • 写入时复制容器,在修改的时候会创建并发布一个新的容器副本。
  • 修改方法(删除、添加)是加锁的,避免多个线程调用产生多个副本。
  • 修改时会复制底层数组,所以需要一定开销,所以适合读远大于写的业务场景。
    Java并发编程:并发容器之CopyOnWriteArrayList(转载)

阻塞队列和生产者-消费者模式

  • BlockingQueue的多种实现:LinkedBlockingQueue、ArrayBlockingQueue是FIFO队列。PriorityBlockingQueue是按优先级排序队列,即可根据元组自然排序来比较元素(如果他们实现Comparable方法),也可以使用Comparator来比较。

双端队列

  • Deque(发音“deck”)和BlockingDeque对Queue、BlockingQueue进行了扩展。Deque是一个双端队列,实现了在队列头和尾高效插入和移除。
  • 实现为ArrayDeque、LinkedBlockingQueue

阻塞方法与中断方法

  • 阻塞:等待I/O操作结束、等待获取一个锁,等待从Thread.sleep方法中醒来、等待另一个线程的计算结果。阻塞线程处于阻塞状态,等待某个不受它控制的事件发生后才能继续执行,当外部事件发生时,线程被置回Runnable(就绪状态)。

  • LinkedBlockingQueue的take、put等方法会抛出InterruptedException与Thread.sleep一样。当方法抛出InterruptedException异常,表示该方法时一个阻塞方法,如果这个方法被中断,那么它将努力提前结束阻塞状态。(只是努力不是保证)

  • LinkedBlockingQueue的take阻塞方法源码

 /** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();

    /** Wait queue for waiting takes */
    private final Condition notEmpty = takeLock.newCondition();

public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                notEmpty.await();
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }
  • 中断,Thread类提供了interrupt方法,用于中断线程或者查询线程是否已经被中断。每个线程都有一个布尔类型的属性,标识线程的中断状态,当中断线程时将设置这个状态。
  • 中断是一种协作机制,一个线程不能强制其它线程停止正在执行的操作而去执行其它的操作。
  • A线程中断B时,A仅仅是要求B在执行到某个可以暂停的地方停止正在执行的动作---前提是如果线程B愿意停止下来。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容