给公司一个业务系统做性能优化时,有个地方需要在循环内实现对外交互。有网络IO的地方很容易出现性能瓶颈,就打算通过parallelStream实现并发操作,
1 2 3 4 5 6 7 |
List resultList = new ArrayList(); xxxList.forEach(item -> { result = doSomethingWithRemoteServer() resultList.add(result) }); return resultList; |
如果直接把forEach
改为parallelStream().forEach
,就会引发新的问题,因为业务代码里使用了 arraylist.add 方法收集计算结果,ArrayList 是非线程安全的使用一个线程安全的容器。
Java里线程安全的集合容器,可以通过如下方法:
Vector
* 古老且线程安全的List, 每次扩容一倍空间,而ArrayList扩容50%。
* 在这个场景下因为集合需要返回上层做额外操作,如果使用Vector
会有不必要的锁开销,当然这点儿性能影响可以忽略不计,如果不想有额外的锁开销就需要在返回时多了一层转换,把Vector转化为ArrayList。
CopyOnWriteArrayList
* 每次添加新元素时创建一个新的List,适合读多写少的场景。该场景基本没并发读的场景,完全没必要使用。
Collections.synchronizedList
* 返回一个包装类SynchronizedList
,对被包装的真实List的所有场景加锁。
其他
* 因为我这里这个场景比较简单也可以使用ConcurrentHashMap
等集合容器来实现线程安全。
我现在的这个场景挺适合Collections.synchronizedList
1 2 3 4 5 6 7 8 9 10 |
List resultList = new ArrayList(); List syncResultList = Collections.synchronizedList(resultList) List resultList = new ArrayList(); xxxList.parallelStream().forEach(item -> { result = doSomethingWithRemoteServer() syncResultList.add(result) }); return resultList; |
全部改完之后,又想到我只用到了 arraylist.add 其实只需要同步这一方法就行了。
1 2 3 4 5 6 7 8 9 |
List resultList = new ArrayList(); xxxList.parallelStream().forEach(item -> { result = doSomethingWithRemoteServer() synchronized(resultList){ resultList.add(result) } }); return resultList; |
这样没有一句废话的实现了多线程环境下,给ArrayList下添加元素。如果还在学生时代,估计我会直接写出最后这种代码,但是随着工作时间久了,习惯于使用各种工具包来实现各种功能,渐渐的忘记最初的样子, 习惯于把简单的问题复杂化。
Keep it simple and stupid.
最新评论
昨天发现的,然后在application.yml中配置“hibernate.dialect.storage_engine=innodb”。但是自动生成的表还是不会设置为innoDB,看了底层源码。这个配置也是没有加载到的 原来是要在hibernate.properties中加这个配置。感谢
将virtualbox虚拟网卡驱动卸载了,然后就会好了,但是这个时候virtualbox虚拟网络就无法使用了,重新安装一下virtualbox就好了
我也发现了这个注释:注释“Use "hibernate.dialect.storage_engine=innodb" environment variable or JVM system property instead.” ----- 坑啊。。。。。。。
卸载蓝牙驱动·在设备里面找,一般在网卡那里 卸载重启就行了
高