6. 集合不安全
1)List 不安全
//java.util.ConcurrentModificationException 并发修改异常!publicclassListTest{publicstaticvoidmain(String[] args){List<Object> arrayList =newArrayList<>();for(int i=1;i<=30;i++){newThread(()->{
arrayList.add(UUID.randomUUID().toString().substring(0,5));System.out.println(arrayList);},String.valueOf(i)).start();}}}
ArrayList 在并发情况下是不安全的
解决方案 :
1.Vector
2.Collections.synchonizedList()
3. CopyOnWriteArrayList
核心思想是,如果有多个调用者(Callers)同时要求相同的资源(如内存或者是磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者视图修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此做法主要的优点是如果调用者没有修改资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。
读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。
多个线程调用的时候,list,读取的时候,固定的,写入(存在覆盖操作);在写入的时候避免覆盖,造成数据错乱的问题;
CopyOnWriteArrayList比Vector效率更高
Vector底层是使用synchronized关键字来实现的 ,效率低
CopyOnWriteArrayList使用的是Lock锁,效率会更加高效!
2)set 不安全
Set和List同理可得:*多线程情况下,*普通的Set集合是线程不安全的;
解决方案还是两种:
- 使用Collections工具类的synchronized包装的Set类
- 使用CopyOnWriteArraySet 写入复制的JUC解决方案
HashSet底层 :
hashSet底层就是一个HashMap
3)Map不安全
//map 是这样用的吗? 不是,工作中不使用这个//默认等价什么? new HashMap<>(16,0.75);Map<String,String> map =newHashMap<>();//加载因子、初始化容量
默认加载因子是0.75,默认的初始容量是16
同样的HashMap基础类也存在并发修改异常!
publicclassMapTest{publicstaticvoidmain(String[] args){//map 是这样用的吗? 不是,工作中不使用这个//默认等价什么? new HashMap<>(16,0.75);/**
* 解决方案
* 1. Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
* Map<String, String> map = new ConcurrentHashMap<>();
*/Map<String,String> map =newConcurrentHashMap<>();//加载因子、初始化容量for(int i =1; i <100; i++){newThread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));System.out.println(map);},String.valueOf(i)).start();}}}
TODO:研究ConcurrentHashMap底层原理:
7. Callable
1、可以有返回值;
2、可以抛出异常;
3、方法不同,run()/call()
Callable和Runnable()区别和联系:
理解Callable怎么和Thread建立联系的!!!
futureTask是一个适配类
Callable的返回结果在futureTask中
获取返回值的操作,可能会产生阻塞
callable线程的结果会缓存,效率更高
publicclassCallableTest{publicstaticvoidmain(String[] args)throwsExecutionException,InterruptedException{for(int i =1; i <10; i++){MyThread1 myThread1 =newMyThread1();FutureTask<Integer> futureTask =newFutureTask<>(myThread1);// 放入Thread中使用,结果会被缓存newThread(futureTask,String.valueOf(i)).start();// 这个get方法可能会被阻塞,如果在call方法中是一个耗时的方法,所以一般情况我们会把这个放在最后,或者使用异步通信int a = futureTask.get();System.out.println("返回值:"+ s);}}}classMyThread1implementsCallable<Integer>{@OverridepublicIntegercall()throwsException{System.out.println("call()");return1024;}}
JUC并发编程-集合不安全情况以及Callable线程创建方式 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧
版权归原作者 666-LBJ-666 所有, 如有侵权,请联系我们删除。