一、ArrayList线程安全问题
1、ArrayList例子
List<String> strings = new ArrayList<>();
//3个线程运行
for (int i=0;i<30;i++)
{
new Thread(()->{
strings.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(strings);
},String.valueOf(i)).start();
}
故障问题,导致原因,如何修改,优化建议
1、故障问题:java.util.ConcurrentModificationException
2、导致原因:并发争抢修改导致 ,一个人在写,另一个在抢,会造成数据不一致。 list出现异常和线程不安全,出现null
2、解决方法
1、如何修改,使用Collections工具类
//使用辅助工具类
List<String> stringsColl = Collections.synchronizedList(new ArrayList<String>());
for (int i=0;i<30;i++)
{
new Thread(()->{
stringsColl.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(stringsColl);
},String.valueOf(i)).start();
}
2、写实复制,读写分离,优化,解决并发
内部用了lock锁加锁后复制新数组并将数组加一再写回去,set进集合里
List<String> objects = new CopyOnWriteArrayList<>();
for (int i=0;i<30;i++)
{
new Thread(()->{
objects.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(objects);
},String.valueOf(i)).start();
}
CopyOnWriteArrayList内部======
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的解决线程安全
1、解决方法
1、使用Collections
/**
* 一解决
*/
Set<String> strings = Collections.synchronizedSet(new HashSet<String>());
for (int i=0;i<30;i++) {
new Thread(()->{
strings.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(strings);
},String.valueOf(i)).start();
}
2、使用CopyOnWriteArraySet
/**
* 二优化,hashSet一个参入得是key,value为写死的final Object
*/
Set copyOnWriteArraySet = new CopyOnWriteArraySet();
for (int i=0;i<30;i++) {
new Thread(()->{
copyOnWriteArraySet.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(copyOnWriteArraySet);
},String.valueOf(i)).start();
}
三、解决hashMap线程不安全
1、解决方法Collections
效率不高,锁太重
//性能太低
Map<String, Object> stringObjectMap = Collections.synchronizedMap(new HashMap<String, Object>());
2、使用ConcurrentHashMap
原理:jdk1.8中抛弃了segment的段锁,只保留segment的结构,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS(自旋)来操作
Map<String, Object> concurrentHashMap = new ConcurrentHashMap<>();
3、线程安全,有序,查询快的集合
跳表遍历
ConcurrentSkipListSet 基于ConcurrentSkipListMap