线程安全的List之CopyOnWriteArrayList
栏目分类:java项目 发布日期:2025-01-27 浏览次数:178 次
ArrayList是线程担心齐的,那面千真万确。原因ArrayList的全部办法既不添锁,也不停止出格的线程平安处置。
而Vector行为线程平安版的ArrayList,生活感老是比拟矮。原因岂论是add、remove仍旧get办法皆加入了synchronized锁,因此服从卑下。
偶然中瞧到挖金中有人写了如许1遍著作(尔花了二地利间出处理的题目,chatgpt用了5秒弄定)
瞅到末了,毕竟来讲是1个多线程停的并提问题,有些人大概以为那个题目很强,然则咋道呢,尔也逢上了。
由于尔按平常逻辑写了1段代码,须要从数据库盘问7次数据,以后觉察屡屡盘查的快度出格缓,因为生意缘故SQL久时没法劣化。
此时料到1个处理意图,便是多条退步碾儿,以停代码模仿了根本淌程
packagecom.example.springboot;importcn.hutool.core.date.DateUtil;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.CountDownLatch;importjava.util.concurrent.Executors;importjava.util.concurrent.ThreadPoolExecutor;publicclassIpTest{publicstaticvoidmain(String[]args){List<String>reList=newArrayList<>();ThreadPoolExecutorpool=(ThreadPoolExecutor)Executors.newFixedThreadPool(7);CountDownLatchcountDownLatch=newCountDownLatch(7);//1周for(inti=0;i<7;i++){CompletableFuture.supplyAsync(()->{try{reList.add(DateUtil.now());}catch(Exceptione){e.printStackTrace();}finally{countDownLatch.countDown();//同步施行停止}returnnull;},pool);}//共步期待查问了局try{countDownLatch.await(30,TimeUnit.SECONDS);}catch(InterruptedExceptione){}reList.stream().forEach(s->System.out.println(s));pool.shutdown();}}CountDownLatch用于干线程窒碍恭候子工作施行完成,参照(Future体制现实运用)
CompletableFuture用于同步施行职司,注重必须正在finally中开释countDownLatch,不然干线程会不绝阻碍30秒。
屡次运转那个模范,您会创造1个题目,偶尔会挨印出去空
2023-06-2909:45:42null2023-06-2909:45:422023-06-2909:45:422023-06-2909:45:422023-06-2909:45:42缘故便是由于ArrayList没有是线程平安。
处理规划有二种
(1)应用synchronized关头字
CompletableFuture.supplyAsync(()->{try{synchronized(reList){reList.add(DateUtil.now());}}catch(Exceptione){e.printStackTrace();}finally{countDownLatch.countDown();//同步施行停止}returnnull;},pool);(2)应用CopyOnWriteArrayList取代
List<String>reList=newCopyOnWriteArrayList<>();对于CopyOnWriteArrayList的诠释,网上1年夜堆,那里面到为行。
那里复杂道停,CopyOnWriteArrayList没有管是add亦好,照样remove也罢。皆是经由过程ReentrantLock + volatile + 数组拷贝去实行线程平安的。
并且屡屡add/remove掌握城市启示新数组,会占用体系内乱存。
然则保存必定也是有利益的,便是get(int index)没有须要添锁,由于CopyOnWriteArrayList正在add/remove操纵时,没有会修正本数组,因此读掌握没有会生存线程平安题目。那本来便是读写别离的心思,惟有写进的时分才添锁,复造正本去停止修正。CopyOnWriteArrayList也啼写时复造容器。
并且正在迭代进程中,便使数组的组织被转变也没有会扔出ConcurrentModificationException同常。由于迭代的一直是本数组,而全部的转变皆爆发正在本数组的正本上。因而对待迭代器来讲,迭代的集中构造没有会产生转变。
概括:CopyOnWriteArrayList的长处重要有二个:
线程平安
年夜年夜的降低了“读”掌握的并收度(比拟于Vector)
舛错也很鲜明:
屡屡“写”操纵城市启示新的数组,虚耗空间
没法保护及时性,由于“读”战“写”没有正在统一个数组,且“读”操纵不添互斥锁,因此没有能包管强分歧性,只可保障终究分歧性
add/remove操纵服从矮,既要添锁,借要拷贝数组
因而CopyOnWriteArrayList较为吻合读多写少的场景。
推举您浏览更多相关于“ list多线程线程平安CopyOnWriteArrayList ”的著作