做微博类的网站难吗,什么值得买网站模板,金钟街网站建设,网络推广的话术怎么说目录
一、多线程环境使用ArrayList
二、多线程环境使用队列
三、多线程环境使用哈希表
1、HashMap
2、Hashtable
3、ConcurrentHashMap
(1)缩小了锁的粒度
(2)充分使用了CAS原子操作#xff0c;减少一些加锁
(3)针对扩容操作的一些优化#xff08;化整为零#xff…目录
一、多线程环境使用ArrayList
二、多线程环境使用队列
三、多线程环境使用哈希表
1、HashMap
2、Hashtable
3、ConcurrentHashMap
(1)缩小了锁的粒度
(2)充分使用了CAS原子操作减少一些加锁
(3)针对扩容操作的一些优化化整为零
四、相关面试题 大部分集合类都是线程不安全的VectorStackHashtable是线程安全的但不建议使用因为无论什么情况都要加锁甚至单线程也是这样就很不合理并且这几个集合类官方已经不推荐使用了可能在未来的版本中就被删掉了。
下面介绍一些线程不安全的集合类。
一、多线程环境使用ArrayList
1、自己使用同步机制synchronized或者ReentrantLock
2、Collections.synchronizedList(new ArrayList); 相当于给ArrayList套了个壳ArrayList各种操作本身是不带锁的通过上述操作套壳后得到了新的对象新的对象里面的关键方法都是带有锁的。
3、使用CopyOnWriteArrayList CopyOnWrite容器即写时复制的容器多线程对这个顺序表进行读操作时不会有线程安全问题但是当多线程进行写操作时就会有线程安全问题CopyOnWriteArrayList会复制一份原来的顺序表并且修改新的顺序表内容再把原来的引用指向新的顺序表(此操作是原子的不需要加锁)。 二、多线程环境使用队列
1、自己加锁
2、使用BlockingQueue 1. ArrayBlockingQueue 基于数组实现的阻塞队列 2. LinkedBlockingQueue 基于链表实现的阻塞队列 3. PriorityBlockingQueue 基于堆实现的带优先级的阻塞队列 4. TransferQueue 最多只包含⼀个元素的阻塞队列 三、多线程环境使用哈希表
1、HashMap HashMap本身就是线程不安全的。
2、Hashtable 在一些关键方法上加了锁 这也相当于对this加了锁也就是针对Hashtable对象本身加锁如果尝试修改Hash表中两个不同Hash值里的链表会发生锁冲突。如图 3、ConcurrentHashMap
相对于Hashtable进行了些优化。
(1)缩小了锁的粒度 多线程如果修改Hash表里Hash值不同的链表都发生锁冲突是不合理的而且锁冲突是很耗时的所以ConcurrentHashMap是对Hash表里每个链表都进行加锁这样不同的链表有不同的锁对象多线程修改两个不同的链表就不会发生锁冲突了如图 注意更多的锁并不意味着要耗费更多的空间因为在java中的任何对象都可以作为锁对象而本身Hash表中就得有数组数组元素都已经存在即链表的头结点每个链表都有一个头结点可以直接把这个头结点作为链表的锁对象。
(2)充分使用了CAS原子操作减少一些加锁 比如针对Hash表元素个数的维护。
(3)针对扩容操作的一些优化化整为零 负载因子描述了每个桶Hash表平均有多少个元素公式实际个数 / 数组长度桶的个数。0.75是默认的扩容阈值也可以是其他数字值如果我们算出的负载因子超过规定的扩容阈值Hash表就会进行扩容。 进行扩容时如果不是concurrentHashMap会创建一个更大是数组把旧的数组元素搬运到新的数组中一次性的全部搬运完如果Hash表本身的元素就非常多这里扩容就会非常耗时但可能过一会儿就又好了存在不稳定因素我们无法控制Hash表何时触发扩容。 concurrentHashMap则不是一次性的全部搬运完而是把Hash表中的元素分为若干次搬运完而不是直接一次性梭哈完假设Hash表有1kw个元素每次就只搬运5k哥元素一共花费2k次搬运完成搬运的时间会更长一些但能确保每次搬运消耗的时间不会很长避免出现很卡的情况。
总的来说扩容是一个低频的操作前提把扩容阈值设置合理运行整个程序可能一天都不会触发扩容触发了每次可能会花费几分钟的时间进行搬运。
注意在扩容过程中存在两份Hash表一份是新的一份是旧的。 进行插入操作直接往新的Hash表上插入。 进行删除操作新的旧的都要删除。 进行查找操作新的旧的都要查找。 四、相关面试题
1.ConcurrentHashMap的读是否要加锁,为什么? 读操作没有加锁.目的是为了进一步降低锁冲突的概率.为了保证读到刚修改的数据,搭配了volatile关键字. 2.介绍下ConcurrentHashMap的锁分段技术? 这个是Java1.7所采取的技术.Java1.8中已经不再使用了.简单的说就是把若干个哈希桶分成一个段(Segment),针对每个段分别加锁. 目的也是为了降低锁冲突的概率.当两个线程访问的数据恰好在同一个段上时,才会触发锁竞争 3.ConcurrentHashMap在jdk1.8做了哪些优化? 取消了分段锁,直接给每个哈希桶(每个链表)分配了一个锁(就是以每个链表的头节点对象作为锁对象). 将原来的数组 链表的实现方式改进成 数组 链表 /红黑树的方式.当链表较长的时候(大于等于8个元素)就转换成红黑树. 4.HashMap和HashTable,ConcurrentHashMap之间的区别? HashMap: 线程不安全.key允许为null HashTable:线程安全.使用synchronized锁HashTable对象,效率较低.key不允许设置为null. ConcurrentHashMap: 线程安全.使用synchronized锁每个链表的头节点,锁冲突概率较低,充分利用CAS机制,优化了扩容方式.key不允许为null. 都看到这了点个赞再走吧谢谢谢谢谢