1.3.3 并发容器类MAP/LIST/SET/QUEUE
HashMap
下标计算方法:hashCode & (length-1) ,&按位与操作,二进制相同位都是1,该位才为1
JDK1.7与JDK1.8中HashMap区别: JDK1.8在put元素时,若计算得到的下标下的链表长度达到8时(算上当前要加到链表尾部的元素),链表会转换成红黑树提高查找效率
通过调整hashmap初始大小避免rehash的实例:要转移1000个数据到hashmap,那么假定初始大小1024,在转移到1024*0.75=768个时会触发rehash,将1024扩容到2048,所以如果在设置初始大小时指定2048就可以避免一次rehash
https://www.cnblogs.com/williamjie/p/9358291.html
hashMap是线程不安全的,hashtable利用synchronized加在put和get方法上实现线程安全
ConcurrentHashMap
线程安全的HashMap
JDK1.7 ConcurrentHashMap有多个HashTable组成,有几个HashTable并发级别concurrencyLevel就是几,默认16,这就叫分段锁,




ConcurrentSkipListMap/TreeMap
TreeMap与HashMap不同之处在于,TreeMap按照key的字典顺序来排序(升序),也可通过Comparator实现排序逻辑
TreeMap线程不安全,使用ConcurrentSkipListMap保证线程安全


ArrayList
非线程安全
CopyOnWriteArrayList
线程安全,通过ReentrantLock实现,add()方法加锁
但会对数组进行拷贝,在某段时间数据量翻倍造成内存溢出,不适用数据量过大的情况
读取新写入的数据会有延迟,因为数组的引用需要从旧数组转到新数组
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
HashSet
HashMap如果遇到相同的Key会对Value值进行覆盖,保证HashMap的Key是不重复的。
HashSet<T> 即利用HashMap这一特性保证Set集合中元素(KEY)不重复,其并不关心Value的值。
CopyOnWriteArraySet
写的时候会判断数组中是否已经存在,若存在就不再写入,其他特性与CopyOnWriteArrayList相同
ConcurrentSkipListSet
跳表实现原理同ConcurrentSkipListMap,KEY不重复且有序
队列QUEUE

ArrayBlockingQueue
线程安全,数组实现,ReentrantLock锁,只有一把锁,take() 和 put() 互斥,加的是同一把锁;
take()和put()方法是阻塞的,offer()和poll()方法是非阻塞的
构造函数制定队列长度capacity,利用参数count记录队列中元素数量,count=capacity时put操作阻塞(poll()方法直接返回null),count=0时take操作阻塞(offer()方法直接返回false),底层唤醒其实是利用condition的2个队列实现,参照1.3.1 Lock利用condition实现的阻塞队列;
put和take时利用takeIndex和putIndex记录下一个操作应该放到那个位置或从哪个位置取;
循环数组实现:当putIndex达到capacity时,takeIndex并不是+1,而是变成0,即下一个put操作会将元素放到队列头部;takeIndex原理相同
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}

LinkedBlockingQueue
线程安全,链表实现,put和take各一把ReentrantLock锁,读和写操作加的是不同的锁,互不干扰,提高了读写性能
take()操作利用takeLock操作链表头部,put()利用putLock操作链表尾部,互不干扰,读和取不会互斥,并发度比ArrayBlockingQueue高一些
ConcurrentLinkedQueue
线程安全,并发度高,非阻塞队列,无锁,没有take() 和 put()这2个阻塞方法
利用CAS操作,采用自旋的方式将元素添加到链表尾部 或 将链表头部替换为null


SynchronousQueue
不常用
package com.study.list_set_queue.queue; import java.util.concurrent.SynchronousQueue; /*
1、take会阻塞,直到取到元素
2、put时会阻塞,直到被get
3、若没有take方法阻塞等待,offer的元素可能会丢失
4、poll取不到元素,就返回null,如果正好有put被阻塞,可以取到
5、peek 永远只能取到null,不能让take结束阻塞 */ public class Demo2_SyncQueueTest {
static SynchronousQueue<String> syncQueue = new SynchronousQueue<>(); //put时会阻塞,直到被get
public static void test01() throws InterruptedException {
new Thread(){
@Override
public void run() {
try {
Thread.sleep(3000L);
System.out.println(syncQueue.poll());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start(); System.out.println("begain to put...");
syncQueue.put("put_element");
System.out.println("put done...");
} //3、若没有take方法阻塞等待,offer的元素可能会丢失
public static void test02() throws InterruptedException {
syncQueue.offer("offered_element"); System.out.println(syncQueue.poll());
} //4、poll取不到元素,就返回null,如果正好有put被阻塞,可以取到
public static void test03() throws InterruptedException {
/* new Thread(){
@Override
public void run() {
try {
syncQueue.put("put_element");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();*/ Thread.sleep(200L);
Object obj = syncQueue.poll();
System.out.println(obj);
} //peek 永远只能取到null,不能让take结束阻塞
public static void test04() throws InterruptedException {
new Thread(){
@Override
public void run() {
try {
syncQueue.put("put_element");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start(); Thread.sleep(200L);
Object obj = syncQueue.peek();
System.out.println(obj);
} public static void main(String args[]) throws InterruptedException {
test02();
}
}
PriorityBlockingQueue
优先级队列,可以通过比较器对入队列的元素进行排序存储,进而改变出队列顺序
package com.study.list_set_queue.queue; import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue; public class Demo4_PriorityBlockingQueue3 {
public static void main(String args[]) {
PriorityBlockingQueue<Student> queue = new PriorityBlockingQueue<>(5, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num1 = o1.age;
int num2 = o2.age; if (num1 > num2)
return 1;
else if (num1 == num2)
return 0;
else
return -1;
}
});
queue.put(new Student(10, "enmily"));
queue.put(new Student(20, "Tony"));
queue.put(new Student(5, "baby")); for (; queue.size() > 0;) {
try {
System.out.println(queue.take().name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} class Student {
public int age;
public String name; public Student(int age, String name) {
this.age = age;
this.name = name;
}
}
1.3.3 并发容器类MAP/LIST/SET/QUEUE的更多相关文章
- java并发容器(Map、List、BlockingQueue)
转发: 大海巨浪 Java库本身就有多种线程安全的容器和同步工具,其中同步容器包括两部分:一个是Vector和Hashtable.另外还有JDK1.2中加入的同步包装类,这些类都是由Collectio ...
- java Concurrent并发容器类 小结
Java1.5提供了多种并发容器类来改进同步容器的性能. 同步容器将所有对容器的访问都串行化,以实现他们的线程安全性.这种方法的代价是严重降低并发性,当多个线程竞争容器的锁时,吞吐量将严重减低. 一 ...
- java并发容器(Map、List、BlockingQueue)具体解释
Java库本身就有多种线程安全的容器和同步工具,当中同步容器包含两部分:一个是Vector和Hashtable.另外还有JDK1.2中增加的同步包装类.这些类都是由Collections.synchr ...
- 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式
上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...
- go语言坑之并发访问map
fatal error: concurrent map read and map write 并发访问map是不安全的,会出现未定义行为,导致程序退出.所以如果希望在多协程中并发访问map,必须提供某 ...
- 映射Map、队列Queue、优先级队列PriorityQueue
映射Map 将对象映射到其他对象的能力是解决编程问题的有效方法.例如,考虑一个程序,它被用来检查 Java 的 Random 类的随机性.理想情况下, Random 会产生完美的数字分布,但为了测试这 ...
- Java并发编程(十四)并发容器类
同步容器将所有对容器状态的访问都串行化,以实现线程安全性.这种方法的代价是严重降低并发性,当多个线程竞争容器的锁时,吞吐量将严重减低. 另一个方面,并发容器是针对多个线程并发访问设计的.在java 5 ...
- 专用于高并发的map类-----Map的并发处理(ConcurrentHashMap)
oncurrentModificationException 在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException, 取 ...
- JDK容器类Map源码解读
java.util.Map接口是JDK1.2开始提供的一个基于键值对的散列表接口,其设计的初衷是为了替换JDK1.0中的java.util.Dictionary抽象类.Dictionary是JDK最初 ...
随机推荐
- Codeforces Round #564 比赛总结
这次是中国大佬出题,结果被虐惨了. A. Nauuo and Votes #include<bits/stdc++.h> #define Rint register int using n ...
- 利用前端三大件(html+css+js)开发一个简单的“todolist”项目
一.介绍 todolist,即待办事项.在windows android ios上参考微软家出的那个To-Do应用,大概就是那样的.我这个更简单,功能只有“待办” “已完成”两项,并且是在浏览器打开的 ...
- 最简单的babel+webpack配置
首先先介绍一下2个重要的库:core-js 和 regenerator core-js core-js 是用于 JavaScript 的组合式标准化库,它包含 es5 (e.g: object.fre ...
- JVM备忘点(1.8以前)
1.内存结构 左边两个线程共享,右边三个线程私有. 方法区:.class文件的类信息.常量.static变量.即时编译器编译后的代码(动态代理).HotSpot将方法区称为永久代 堆:分为新生代和老年 ...
- 1-7HSB色彩模式
http://www.missyuan.com/thread-350721-1-1.html HSB色彩模式色相hue.饱和度saturation.明度brightness 在HSB模式中,S和B的取 ...
- 安装openssh-server
以前在服务器上装过openssh-server,今天突然想把台式机也打开ssh服务,结果忘了咋弄,稍微百度了一下就弄好了,备忘一下,以后就不用各种百度了. 第一步,安装openssh-server( ...
- arcgis根据表字段进行数据合并
第一步 1.地理处理-----2.数据管理工具----3.制图综合----4.融合 第二步 打开融合面板,选择输入要素,要融合的字段,选择统计字段数量,完成融合.
- 【Python】使用Python处理RAW格式图片,并根据实际情况完成分组打包发送
背景 出游之后,朋友交换的照片格式大多是RAW格式,一些人想要JPG格式,但是百度云盘非会员的下载速度惨不忍睹,所以我想着通过微信群直接传(这个在事后也被证实不能完全解决问题,微信限制了每天传递文件的 ...
- windows下安装node.js及环境配置、部署项目
windows下安装node.js及环境配置.部署项目 一.总结 一句话总结: 安装nodejs软件:就像普普通通的的软件那样安装 配置nodejs安装的全局模块的环境变量 并且安装cnpm(比如cn ...
- 粘性定位 sticky
position:sticky 粘性定位 top:200px 这是他的阈值,意思是当我们页面滚动到 200 像素的使用,我们的元素会自动变成固定定位,不到200像素的时候,我们的元素走的是相对定位 ...

