当前位置: 首页 > news >正文

商会 网站模板优化营商环境心得体会

商会 网站模板,优化营商环境心得体会,网络工程师面试题,最简单的网站模板遍历List的多种方式 在讲如何线程安全地遍历List之前&#xff0c;先看看通常我们遍历一个List会采用哪些方式。 方式一&#xff1a; for(int i 0; i < list.size(); i) {System.out.println(list.get(i)); } 方式二&#xff1a; Iterator iterator list.iterator(); …

遍历List的多种方式

在讲如何线程安全地遍历List之前,先看看通常我们遍历一个List会采用哪些方式。

方式一:

for(int i = 0; i < list.size(); i++) {System.out.println(list.get(i));
}

方式二:

Iterator iterator = list.iterator();
while(iterator.hasNext()) {System.out.println(iterator.next());
}

方式三:

for(Object item : list) {System.out.println(item);
}

方式四(Java 8):

list.forEach(new Consumer<Object>() {@Overridepublic void accept(Object item) {System.out.println(item);}
});

方式五(Java 8 Lambda):

list.forEach(item -> {System.out.println(item);
});

方式一的遍历方法对于RandomAccess接口的实现类(例如ArrayList)来说是一种性能很好的遍历方式。但是对于LinkedList这样的基于链表实现的List,通过list.get(i)获取元素的性能差。

方式二和方式三两种方式的本质是一样的,都是通过Iterator迭代器来实现的遍历,方式三是增强版的for循环,可以看作是方式二的简化形式。

方式四和方式五本质也是一样的,都是使用Java 8新增的forEach方法来遍历。方式五是方式四的一种简化形式,使用了Lambda表达式。

遍历List的同时操作List会发生什么?

先用非线程安全的ArrayList做个试验,用一个线程遍历List,遍历的同时另一个线程删除List中的一个元素,代码如下:

public static void main(String[] args) {// 初始化一个list,放入5个元素final List<Integer> list = new ArrayList<>();for(int i = 0; i < 5; i++) {list.add(i);}// 线程一:通过Iterator遍历Listnew Thread(new Runnable() {@Overridepublic void run() {for(int item : list) {System.out.println("遍历元素:" + item);// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();// 线程二:remove一个元素new Thread(new Runnable() {@Overridepublic void run() {// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}list.remove(4);System.out.println("list.remove(4)");}}).start();
}

运行结果:
遍历元素:0
遍历元素:1
list.remove(4)
Exception in thread “Thread-0” java.util.ConcurrentModificationException

线程一在遍历到第二个元素时,线程二删除了一个元素,此时程序出现异常:ConcurrentModificationException。

试想如果一个老师正在点整个班级所有学生的人数(线程一遍历List),而校长(线程二)同时叫走几个学生,那么老师也肯定点不下去了。

所以我们会想到一个解决方案,那就是校长等待老师点完学生后,再叫走学生。即让线程二等待线程一的遍历完成后再进行remove元素。

使用线程安全的Vector

ArrayList是非线程安全的,Vector是线程安全的,那么把ArrayList换成Vector是不是就可以线程安全地遍历了?

将程序中的:

final List<Integer> list = new ArrayList<>();

改成:

final List<Integer> list = new Vector<>();

再运行一次试试,会发现结果和ArrayList一样会抛出ConcurrentModificationException异常。

为什么线程安全的Vector也不能线程安全地遍历呢?其实道理也很简单,看Vector源码可以发现它的很多方法都加上了synchronized来进行线程同步,例如add()、remove()、set()、get(),但是Vector内部的synchronized方法无法控制到遍历操作,所以即使是线程安全的Vector也无法做到线程安全地遍历。

如果想要线程安全地遍历Vector,需要我们去手动在遍历时给Vector加上synchronized锁,防止遍历的同时进行remove操作。相当于校长等待老师点完学生后,再叫走学生。代码如下:

public static void main(String[] args) {// 初始化一个list,放入5个元素final List<Integer> list = new Vector<>();for(int i = 0; i < 5; i++) {list.add(i);}// 线程一:通过Iterator遍历Listnew Thread(new Runnable() {@Overridepublic void run() {// synchronized来锁住list,remove操作会在遍历完成释放锁后进行synchronized (list) {for(int item : list) {System.out.println("遍历元素:" + item);// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}).start();// 线程二:remove一个元素new Thread(new Runnable() {@Overridepublic void run() {// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}list.remove(4);System.out.println("list.remove(4)");}}).start();
}

运行结果:
遍历元素:0
遍历元素:1
遍历元素:2
遍历元素:3
遍历元素:4
list.remove(4)

运行结果显示list.remove(4)的操作是等待遍历完成后再进行的。

CopyOnWriteArrayList

CopyOnWriteArrayList是java.util.concurrent包中的一个List的实现类。CopyOnWrite的意思是在写时拷贝,也就是如果需要对CopyOnWriteArrayList的内容进行改变,首先会拷贝一份新的List并且在新的List上进行修改,最后将原List的引用指向新的List。

使用CopyOnWriteArrayList可以线程安全地遍历,因为如果另外一个线程在遍历的时候修改List的话,实际上会拷贝出一个新的List上修改,而不影响当前正在被遍历的List。

相当于校长要想从班级喊走或者添加学生,需要把学生全部带到一个新的教室再进行操作,而老师则通过之前班级的快照在照片上清点学生。

public static void main(String[] args) {// 初始化一个list,放入5个元素final List<Integer> list = new CopyOnWriteArrayList<>();for(int i = 0; i < 5; i++) {list.add(i);}// 线程一:通过Iterator遍历Listnew Thread(new Runnable() {@Overridepublic void run() {for(int item : list) {System.out.println("遍历元素:" + item);// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();// 线程二:remove一个元素new Thread(new Runnable() {@Overridepublic void run() {// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}list.remove(4);System.out.println("list.remove(4)");}}).start();
}

运行结果:
遍历元素:0
遍历元素:1
list.remove(4)
遍历元素:2
遍历元素:3
遍历元素:4

从上面的运行结果可以看出,虽然list.remove(4)已经移除了一个元素,但是遍历的结果还是存在这个元素。由此可以看出被遍历的和remove的是两个不同的List。

线程安全的List.forEach

List.forEach方法是Java 8新增的一个方法,主要目的还是用于让List来支持Java 8的新特性:Lambda表达式。

由于forEach方法是List的一个方法,所以不同于在List外遍历List,forEach方法相当于List自身遍历的方法,所以它可以自由控制是否线程安全。

我们看线程安全的Vector的forEach方法源码:

public synchronized void forEach(Consumer<? super E> action) {...
}

可以看到Vector的forEach方法上加了synchronized来控制线程安全的遍历,也就是Vector的forEach方法可以线程安全地遍历

下面可以测试一下:

public static void main(String[] args) {// 初始化一个list,放入5个元素final List<Integer> list = new Vector<>();for(int i = 0; i < 5; i++) {list.add(i);}// 线程一:通过Iterator遍历Listnew Thread(new Runnable() {@Overridepublic void run() {list.forEach(item -> {System.out.println("遍历元素:" + item);// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}}).start();// 线程二:remove一个元素new Thread(new Runnable() {@Overridepublic void run() {// 由于程序跑的太快,这里sleep了1秒来调慢程序的运行速度try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}list.remove(4);System.out.println("list.remove(4)");}}).start();
}

运行结果:
遍历元素:0
遍历元素:1
遍历元素:2
遍历元素:3
遍历元素:4
list.remove(4)

转载请注明原文地址:http://xxgblog.com/2016/04/02/traverse-list-thread-safe/

http://www.lbrq.cn/news/2456137.html

相关文章:

  • 做网站用什么数据库百度指数功能模块有哪些
  • 江北关键词优化排名seoseo快速排名外包
  • 酒店网站素材专业网站建设公司
  • 私密浏览器免费版图片外贸谷歌seo
  • 中铁快运关于网站建设郑州做网络优化的公司
  • wordpress 网站首页可以打开_其他页面打不开太原seo快速排名怎么样
  • 听歌网站源码最新军事头条
  • asp做购物网站手机百度搜索
  • 背景素材网零基础seo入门教学
  • 网站建设需求文档模板免费的编程自学网站
  • 微网站怎么做的网站seo主要是做什么的
  • 上海网站se0优化elo机制
  • 有什么网站可以自己做书百度云官网登录入口
  • 查询项目经理有无在建沈阳seo关键词排名
  • 衡阳网站建设公司电话b站推广入口
  • 临沂网站建设企业唐山seo快速排名
  • wordpress做分类信息网站网络营销ppt怎么做
  • 企业的网站建设怎么记科目重庆高端seo
  • wordpress修改文章字体颜色安卓优化大师新版
  • 彭州做网站的公司口碑营销的形式
  • 国外网站建设推广短视频培训课程
  • 我有域名怎么做网站百度提交网站收录入口
  • wordpress如何关注博客外贸网站推广与优化
  • 智能建站系统cms淘宝标题优化工具推荐
  • 建wap网站友情链接网址
  • 2023年北京疫情怎么样了河北seo诊断培训
  • 网站备案查询怎么查销售平台
  • 做接口自动化是网站登录加密莆田百度快照优化
  • 资深的金融行业网站开发东莞疫情最新消息今天
  • 山西大同网站建设价格app接入广告变现
  • php算法-- 关联数组使用,优化sip账号去重
  • NLP验证自动化脚本优化
  • “磁”力全开:钕铁硼重塑现代科技生活
  • 详谈OSI七层模型和TCP/IP四层模型以及tcp与udp为什么是4层,http与https为什么是7层
  • C++20协程异步
  • uboot FPGA调试环境搭建