java总结

CopyOnWrite容器

  • CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,
  • 不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的
  • 容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是
  • 我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任
  • 何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
  • 具体的实现类:
  • CopyOnWriteArrayList和CopyOnWriteArraySet(具体实现为CopyOnWriteArrayList)
  • CopyOnWriteArrayList的实现原理
  • 可以发现在添加的时候是需要加锁的,否则多线程写的时候会Copy出N个副本出来。读的时候
  • 不需要加锁,如果读的时候有多个线程正在向ArrayList添加数据,读还是会读到旧的数据,
  • 因为写的时候不会锁住旧的ArrayList
  • CopyOnWriteArrayList每次添加元素都是在原始数组的长度基础上+1,删除元素则长度-1
  • CopyOnWrite的应用场景
  • CopyOnWrite并发容器用于读多写少的并发场景。
  • 比如白名单,黑名单,商品类目的访问和更新场景,假如我们有一个搜索网站,用户在这个网
  • 站的搜索框中,输入关键字搜索内容,但是某些关键字不允许被搜索。这些不能被搜索的关键
  • 字会被放在一个黑名单当中,黑名单每天晚上更新一次。当用户搜索时,会检查当前关键字在
  • 不在黑名单当中,如果在,则提示不能搜索
  • 注意两点:
    • 减少扩容开销。根据实际需要,初始化一个Set,将数据全局添加到set中,然后再使用
  • addAll之类的方法一行添加集合中的所有元素,以避免每次写时扩容的开销,合理的评估
    • 使用批量添加。因为每次添加,容器每次都会进行复制,所以减少添加次数,可以减少容器
  • 的复制次数。

CopyOnWrite的缺点

1、内存占用问题。因为CopyOnWrite的写时复制机制,所以在进行写操作的时候,内存里会 同时驻扎两个对象的内存,旧的对象和新写入的对象(注意:在复制的时候只是复制容器里的 引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份 对象内存)。 针对内存占用问题,可通过压缩容器中的元素的方法来减少大对象的内存消耗,如果元素全是 10进制的数字,可以考虑把它压缩成36进制或64进制。或者不使用CopyOnWrite容器,而使 用其他的并发容器,如ConcurrentHashMap。 2、数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一 致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。

ConcurrentSkipListMap

ConcurrentSkipListSet

二分查找要求元素可以随机访问,所以决定了需要把元素存储在连续内存。这样查找确实很快,但是插入和删除元素的时候,为了保证元素的有序性,就需要大量的移动元素了。

如果需要的是一个能够进行二分查找,又能快速添加和删除元素的数据结构,首先就是二叉查找树,二叉查找树在最坏情况下可能变成一个链表。

于是,就出现了平衡二叉树,根据平衡算法的不同有AVL树,B-Tree,B+Tree,红黑树等,但是AVL树实现起来比较复杂,平衡操作较难理解,这时候就可以用SkipList跳跃表结构。

monitor

Monitor可以翻译成监视器或者管程,是由JVM提供的,当线程执行到对象方法的临界区时,首先去看对象头是

不是关联了Monitor,如果关联了加入Monitor的EntryList中,没有关联就改变对象的对象头的Mark Word或者指

向一个Monitor,然后Monitor的拥有者就变成了该线程,执行完了之后,Monitor再把线程释放,去EntryList找

一个新的拥有者(非公平竞争,不是先来的就先得)

  • 一个对象关联一个Monitor;当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时

,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁

  • Java虚拟机给每个对象和class字节码都设置了一个监听器Monitor,用于检测并发代码的重入,同时在

Object类中还提供了notify和wait方法来对线程进行控制

  • 重量级锁也就是通常说synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(也称为管程

或监视器锁)的起始地址

  • 不加synchronized的对象不会关联监视器;
  • 自旋优化:在竞争锁的时候,自旋重试几次,要是此时锁被释放就进入,否则进入阻塞状态

java中每个对象都有唯一的一个monitor,想拥有一个对象的monitor的话有以下三种方式:

1、执行该对象的同步方法public synchronize a () {}

2、执行该对象的同步块synchronize(obj) {} 3、执行某个类的静态同步方法public static synchronize b(){}`。

Monitor可以类比为一个特殊的房间,这个房间中有一些被保护的数据,Monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据,进入房间即为持有Monitor,退出房间即为释放Monitor。

当一个线程需要访问受保护的数据(即需要获取对象的Monitor)时,它会首先在entry-set入口队列中排队(这里并不是真正的按照排队顺序),如果没有其他线程正在持有对象的Monitor,那么它会和entry-set队列和wait-set队列中的被唤醒的其他线程进行竞争(即通过CPU调度),选出一个线程来获取对象的Monitor,执行受保护的代码段,执行完毕后释放Monitor,如果已经有线程持有对象的Monitor,那么需要等待其释放Monitor后再进行竞争。

容错机制

failfast快速失败

  • 如果出现故障,则立即报错。
  • 通常用于非幂等性操作,如:下单操作,如果写入故障,则立即报错,不必重试

failsafe故障安全

  • 如果出现故障,则可以忽略,因为这种故障不会造成损失或损失在可接受范围内。
  • 通常用于辅助性操作,如:写入监控日志,如果写入故障,则忽略。

failover故障切换

  • 如果出现故障,则重试备份操作模式。
  • 通常用于幂等性操作,如:MySql的双Master模式,如果主Master故障,则切换至从Master。
  • 重试通常会带来更多延时。

failback故障恢复

  • 故障切换之后,如果主要操作模式恢复,则自动从备份操作模式恢复主要操作模式。
  • 如:MySql的双Master模式,如果主Master故障,则failover至从Master;当主Master恢复之

后,则自动切换至主Master。

快速失败

  • fail-fast的字面意思是快速失败。当在遍历集合元素时,经常会使用迭代器,但在迭代器遍历元素的过程中
  • ,如果集合的结构被改变的话,就会抛出异常,防止继续遍历。这就是所谓的快速失败机制。
  • fail-fast即快速失败机制,它是java集合中的一种错误检测机制,当多个线程(当个线程也是可以),在结
  • 构上对集合进行改变时,就有可能会产生fail-fast机制。
  • 当Iterator这个迭代器被创建后,除了迭代器本身的方法(remove)可以改变集合的结构外,其他的因素如若
  • 改变了集合的结构,都被抛出ConcurrentModificationException异常。ListIterator---list
  • 原理:
  • modCount和Iterator实现类中的expectedModCount
  • fail-safe与fail-fast的区别
  • 当我们对集合结构上做出改变的时候,fail-fast机制就会抛出异常。但是,对于采用fail-safe机制来说,
  • 就不会抛出异常。这是因为,当集合的结构被改变的时候,fail-safe机制会在复制原集合的一份数据出来,
  • 然后在复制的那份数据遍历。
  • 因此,虽然fail-safe不会抛出异常,但存在以下缺点:
    1. 复制时需要额外的空间和时间上的开销。
    1. 不能保证遍历的是最新内容。
    • Java.util包中的所有集合类都被设计为fail-fast快速失败,java.util.concurrent 中的集合类都为
  • fail-safe安全失败的
    • Fail-fast迭代器抛出ConcurrentModificationException,Fail-safe迭代器从不抛出ConcurrentMod
  • ificationException
    • 安全失败Fail-Safe 类型的数据结构,当集合对象发生结构性修改时不会抛出任何异常。这是因为迭代器
  • 在执行开始前,基于原集合类元拷贝了一份元素副本,因此迭代器执行的操作,如遍历、添加或删除等,并
  • 非原集合类对象的内部元素
  • 集合容错总结

Fail Fast 迭代器的几个关键点:

  • 遍历时一旦发现原集合对象发生修改则会抛出 ConcurrentModificationException
  • 被遍历的是原集合对象的元素
  • 这类迭代器不需要额外内存空间

Fail Safe 迭代器的几个关键点:

  • 允许在进行迭代时对原集合对象的元素进行修改
  • 在遍历的同时修改集合对象的元素,不会抛出任何异常
  • 一种实现是:遍历的是原集合类对象元素的拷贝,需要额外的内存空间用于拷贝的元素数组。另一种实现

是:weakly consistent,内存弱一致性。

数据结构

Fail-Fast

  • ArrayList、LinkedList、Vector【虽然是线程安全的】
  • HashSet、LinkedHashSet、TreeSet
  • HashMap、LinkedHashMap、TreeMap、Hashtable【虽然是线程安全的】
  • Collections.synchronizedXXX() 包装出的【虽然是线程安全的】

Fail-Safe

  • CopyOnWriteArrayList
  • CopyOnWriteArraySet
  • ConcurrentSkipListSet
  • ConcurrentHashMap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值