线程安全的集合
线程安全的集合
- CopyOnWriteArrayList
- 线程安全的ArrayList,加强版的读写分离。
- 写有锁,读无锁,读写之间不阻塞,由于读写锁。
- 写入时,先copy一个容器副本、再添加新元素,最后替换引用。(浪费空间)
- 使用方式与ArrayList无异。
package com.sun.base.XianCheng;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 使用多线程操作CopyOnWriteArrayList
*/
public class Mylist {
public static void main(String[] args) {
//创建集合
List<String> list=new CopyOnWriteArrayList<>();
//创建线程池
ExecutorService es = Executors.newFixedThreadPool(5);
//提交任务
for (int i=0;i<5;i++){
es.submit(new Runnable() {
@Override
public void run() {
for (int j =0;j<10;j++){
list.add(Thread.currentThread().getName()+"---"+new Random().nextInt(1000));
}
}
});
}
//关闭线程池
es.shutdown();
while (!es.isTerminated()){}
//打印结果
System.out.println(list.size());
for (String str:list) {
System.out.println(str.toString());
}
}
}
- CopyOnWriteArraySet
- 线程安全的Set,底层使用CopyOnWriteArrayList实现。
- 唯一不同在于,使用addIfAbsent()添加元素,会遍历数组,如存在元素,则不添加(扔掉副本)。
- 重复依据:equals方法。
package com.sun.base.XianCheng;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 演示CopyOnWriteArraySet
*/
public class MySet {
public static void main(String[] args) {
//创建集合
CopyOnWriteArraySet<String> strings = new CopyOnWriteArraySet<>();
//添加元素
strings.add("aaa");
strings.add("bbb");
strings.add("ccc");
strings.add("ddd");
strings.add("aaa");
//打印
System.out.println("元素个数:"+strings.size());
System.out.println(strings.toString());//有序
}
}
Queue接口(队列)
-
Collection的子接口,表示队列FIFO(先进先出)
-
常见方法:
- 抛出异常:
- boolean add(E e)//顺序添加一个元素(到达上限后,再添加则会抛出异常)
- E remove()//获得第一个元素并移除(如果队列没有元素时,则抛出异常)
- E element()//获得第一个元素但不移除(如果队列没有元素时,则会抛出异常)
- 返回特殊值:推荐使用
- boolean offer(E e)//顺序添加一个元素(到达上限后,再添加则会返回false)
- E poll()//获得第一个元素并移除(如果队列没有元素时,则返回null)
- E peek()//获得第一个元素但不移除(如果队列没有元素时,则返回null)
- 抛出异常:
-
ConcurrentLinkedQueue
- 线程安全、可高效读写的队列,高并发下性能最好的队列。
- 无锁、CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)
- V:要更新的变量;E:预期值;N:新值。
- 只有当VE时,VN;否则表示已被更新过,则取消当前操作。
package com.sun.base.XianCheng;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* ConcurrentLinkedQueue的使用
*/
public class MyConcurrentLinkedQueue {
public static void main(String[] args) throws InterruptedException {
//创建安全队列
ConcurrentLinkedQueue<Integer> integers = new ConcurrentLinkedQueue<>();
//创建线程
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 5; i++) {
integers.offer(i);
}
}
});
Thread thread1=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 6; i <= 10; i++) {
integers.offer(i);
}
}
});
//启动线程
thread.start();
thread1.start();
thread.join();
thread1.join();
//出队
int size=integers.size();
for (int i=0;i<size;i++){
System.out.println(integers.poll());
}
}
}
-
BlockingQueue接口(阻塞队列)
-
Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。
-
方法:
- void put(E,e) //将指定的元素插入次队列中,如果没有可用空间,则等待。
- E take() //获取并移除次队列头部元素,如果没有可用元素,则等待。
-
可用于解决生产者、消费者问题。
-
实现类
-
ArrayBlockingQueue:数组结构实现,有界队列。(手工固定上限)
package com.sun.base.XianCheng; import java.util.concurrent.ArrayBlockingQueue; /** * 阻塞队列的使用 * 案例1:实现生产者和消费者 */ public class MyBlockingQueue { public static void main(String[] args) throws InterruptedException { //创建一个有界队列 ArrayBlockingQueue<Integer> strings = new ArrayBlockingQueue<>(6);//固定面包上限为6 //创建两个线程 Thread t1=new Thread(new Runnable() { @Override public void run() { for (int i=1;i<20;i++){ try { strings.put(i); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"生产了第"+i+"号面包"); } } },"小明"); Thread t2=new Thread(new Runnable() { @Override public void run() { for (int i=1;i<20;i++){ try { strings.take(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"消费了第"+i+"号面包"); } } },"小红"); t1.start(); t2.start(); } } -
LinkedBlockingQueue:链表结构实现,有界队列。(默认上限Integer.MAX_VALUE)
-
-
-
ConcurrentHashMap
- 初始容量默认为16段(Segment),使用分段锁设计。
- 不对整个Map加锁,而是为每个Segment加锁。
- 当多个对象存入同一个Segment时,才需要互斥。
- 最理想状态为16个对象分别存入16个Segment,并行数量16。
- 使用方式与HashMap无异。
package com.sun.base.XianCheng;
import java.util.concurrent.ConcurrentHashMap;
/**
* ConcurrentHashMap的使用
*/
public class MyConcurrentHashMap {
public static void main(String[] args) {
//创建集合
ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();
//使用多线程添加数据
for (int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
for (int j=0;j<4;j++){
hashMap.put(Thread.currentThread().getName()+"---"+j,j+" ");
System.out.println(hashMap);
}
}
}).start();
}
}
}

浙公网安备 33010602011771号