线程安全的集合类
List
- CopyOnWriteArrayList
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class UnsafeList {
public static void main(String[] args) {
List<String> list = Arrays.asList("1", "2", "3");
list.forEach(System.out::println);
ArrayList<String> list1 = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
new Thread(()->{
list1.add(UUID.randomUUID().toString().substring(0,4));
System.out.println(list1);
},String.valueOf(i)).start();
}
}
//java.util.ConcurrentModificationException 并发修改异常
//解决方法:
//1.new Vector<>();
//2.Collections.synchronizedList();
//3.new CopyOnWriteArrayList<>(); JUC包下
}
- new CopyOnWriteArrayList<>():写入时复制,读取时固定,写入时避免覆盖造成数据问题。
CopyOnWriteArraySet
package com.cyl.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
public class Set01 {
public static void main(String[] args) {
Set<String> set = Collections.synchronizedSet(new HashSet<>());
CopyOnWriteArraySet<Object> set1 = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 10; i++) {
new Thread(()->{
set1.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set1);
},String.valueOf(i)).start();
}
}
}
HashSet底层是什么?
public HashSet() {
map = new HashMap<>();
}
//add:本质即map的key是无法重复的
public boolean add(E e) {
return map.put(e,PRESENT)==null;
}
private static final Object PRESENT = new Object();
- 底层使用了HashMap中的Key。
ConcurrentHashMap
package com.cyl.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
// java.util.ConcurrentModificationException
public class Map01 {
public static void main(String[] args) {
//map是这样用的吗?默认等价于什么?new HashMap<>(16,0.75);
//加载因子,初始化容量(0.75)
Map<Object, Object> map = new HashMap<>();
//线程安全的
ConcurrentHashMap<Object, Object> map1 = new ConcurrentHashMap<>();
for (int i = 1; i <= 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(),
UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
ConcurrentHashMap原理初探
- ConcurrentHashMap和HashMap一样都是采用拉链法处理哈希冲突,且都为了防止单链表过长影响查询效率,所以当链表长度超过某一个值时候将用红黑树代替链表进行存储,采用了数组+链表+红黑树的结构
- 所以从结构上看HashMap和ConcurrentHashMap还是很相似的,只是ConcurrentHashMap在某些操作上采用了CAS + synchronized来保证并发情况下的安全。
- 说到ConcurrentHashMap处理并发情况下的线程安全问题,这不得不提到Hashtable,因为Hashtable也是线程安全的
- Hashtable采用对象锁(synchronized修饰对象方法)来保证线程安全,也就是一个Hashtable对象只有一把锁,如果线程1拿了对象A的锁进行有synchronized修饰的put方法,其他线程是无法操作对象A中有synchronized修饰的方法的(如get方法、remove方法等),竞争激烈所以效率低下。
- ConcurrentHashMap采用CAS+synchronized来保证并发安全性,且synchronized关键字不是用在方法上而是用在了具体的对象上,实现了更小粒度的锁,
- Hashtable采用的是数组+链表,当链表过长会影响查询效率
- 而ConcurrentHashMap采用数组+链表+红黑树,当链表长度超过某一个值,则将链表转成红黑树,提高查询效率。
Callable接口
- callable接口类似于Runnable接口,因为他们都是为其实例可能由另一个线程执行的类设计的。而Runnable不返回结果,也不抛出异常。
- runnable接口没有返回值,Callable有返回值,可抛出异常
package com.cyl.Callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread thread = new MyThread();
//适配类
FutureTask futureTask = new FutureTask(thread);
new Thread(futureTask,"A").start();
String s1 = (String) futureTask.get();//获取返回结果
System.out.println(s1);
}
}
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
return "null";
}
}