常见的有哪些是线程不安全的?
1、集合类是不安全的:ArrayList,HashSet,HashMap等等都是不安全
2、i++, ++i 也是不安全
JUC什么?
1、juc是java.util.concurrent包的简称,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池、异步IO 和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的Collection 实现等
2、高并发最容易出现的异常是:
ConcurrentModificationException
3、高并发的项目不能使用ArraryList,只能使用juc报下的集合
* 1 lambda Express
* 1.1 如何写: 拷贝形括号,写死右箭头,落地大括号
* 1.2 Lamdba 有且仅有一个方法,注解@FunctionalInterface
* 1.3 default
* 1.4 静态方法
一、题目:请举例说明集合类是不安全的—–面试题
List<String> list = new ArrayList<String>();
for (int i = 1; i <=30; i++)
{
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(1,4));
System.out.println(list);
},String.valueOf(i)).start();
}
运行该代码会报:ConcurrentModificationException异常
为什么会出现这种情况?1.5版本之前是使用的线程安全,但是为了效率改成了不安全的,详情见https://blog.csdn.net/u012859681/article/details/78206494
二、使用JUC解决
原理:写时复制,这个类似于mysql的读写分离
CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy, 复制出一个新的容器Object[] newElements,然后新的容器Object[] newElements里添加元素,添加完元素之后,
再将原容器的引用指向新的容器 setArray(newElements);。这样做的好处是可以对CopyOnWrite容器进行并发的读,
而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] ele ments = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
实现代码:
list—-CopyOnWriteArrayList
set—-CopyOnWriteArraySet
map—ConcurrentHashMap
List<String> list = new CopyOnWriteArrayList<String>();
for (int i = 1; i <=30; i++)
{
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(1,4));
System.out.println(list);
},String.valueOf(i)).start();
}
Set<String> set = new CopyOnWriteArraySet<String>();
for (int i = 1; i <=30; i++)
{
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(1,4));
System.out.println(set);
},String.valueOf(i)).start();
}
Map<String,String> map = new ConcurrentHashMap<String,String>();
for (int i = 1; i <=30; i++)
{
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(1,4));
System.out.println(map);
},String.valueOf(i)).start();
}