线程安全集合类中的对象是安全的么?

2022年01月15日 阅读数:6
这篇文章主要向大家介绍线程安全集合类中的对象是安全的么?,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

以前的文章Java并发BUG基础篇​中提到过线程安全的集合类如​​CopyOnWriteArrayList​​​、​​ConcurrentHashMap​​等的使用,以及线程安全类的几种建立方法:java

Map<String, String> map = Collections.synchronizedMap(new HashMap<>());

List<Integer> list = Collections.synchronizedList(new ArrayList<>());

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

Map<String, String> map = new ConcurrentHashMap<>();

这些JDK中自带的集合类是很是好用的,使用方法很是简单,你们有需求的能够本身写个Demo测试一下。下面是我写的一个Demo,为了验证一个问题:如何在线程安全的类中存放不安全的对象,那么对于集合中对象的访问是线程安全的吗?数组

下面是我测试在集合中存放不安全的对象的Demo:安全

package com.fun

import com.fun.base.constaint.ThreadLimitTimesCount
import com.fun.frame.SourceCode

import java.util.concurrent.ConcurrentHashMap

class TSSS extends SourceCode {

static ConcurrentHashMap<Integer, List<Integer>> map = new ConcurrentHashMap<>()

static List<Integer> list = new ArrayList<>()


public static void main(String[] args) {
map.put(1, list)
30.times {
list.add(4)
}
def tt = new TT(5)

new com.fun.frame.excute.Concurrent(tt * 5).start()

output(map.get(1).size())
}

static class TT extends ThreadLimitTimesCount {

public TT(int time) {
super(null, time, null)
}

@Override
protected void doing() throws Exception {
list.remove(3)
}

public TT clone() {
return new TT(times)
}
}
}

控制台输出结果以下:并发

INFO-> 当前用户:fv,IP:192.168.0.100,工做目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.3
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 总计5个线程,共用时:0.109 s,执行总数:25,错误数:0,失败数:0
INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/fun/long/5FunTester
INFO->
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
> {
> ① . "rt":3,
> ① . "total":25,
> ① . "qps":1329.787234042553,
> ① . "excuteTotal":25,
> ① . "failRate":0.0,
> ① . "threads":5,
> ① . "startTime":"2020-02-24 18:13:23",
> ① . "endTime":"2020-02-24 18:13:23",
> ① . "errorRate":0.0,
> ① . "table":"",
> ① . "desc":"FunTester"
> }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
INFO->
INFO-> 8

Process finished with exit code 0

最后输出结果是8,可见:在线程安全集合中存放的非线程安全类依然是不安全的,具体缘由能够从​​list.remove()​​方法中得见:ide

public E remove(int index) {
rangeCheck(index);

modCount++;
E oldValue = elementData(index);

int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work

return oldValue;
}

先检查,而后去处理一些数据,而后将index后面的数组复制一遍向前移动一位索引,而后就数组最后一位设置为​​null​​​并将数组的​​size​​​减一。在并发情况下,可能会有多个线程进行数组拷贝时使用的是一个​​size​​​,​​index​​​是固定的,由于以前访问这个​​list​​​的线程并无完成对​​size​​的修改赋值。测试

下面我将​​ArrayList​​​替换成线程安全的​​vector​​类,代码以下:编码

package com.fun

import com.fun.base.constaint.ThreadLimitTimesCount
import com.fun.frame.SourceCode

import java.util.concurrent.ConcurrentHashMap

class TSSS extends SourceCode {

static ConcurrentHashMap<Integer, List<Integer>> map = new ConcurrentHashMap<>()

static List<Integer> list = new Vector<>()


public static void main(String[] args) {
map.put(1, list)
30.times {
list.add(4)
}
def tt = new TT(5)

new com.fun.frame.excute.Concurrent(tt * 5).start()

output(map.get(1).size())
}

static class TT extends ThreadLimitTimesCount {

public TT(int time) {
super(null, time, null)
}

@Override
protected void doing() throws Exception {
map.get(1).remove(3)
}

public TT clone() {
return new TT(times)
}
}
}

控制台控制台输出结果以下:spa

INFO-> 当前用户:fv,IP:192.168.0.100,工做目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.3
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 执行次数:5,错误次数: 0,总耗时:1 s
INFO-> 总计5个线程,共用时:0.115 s,执行总数:25,错误数:0,失败数:0
INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/fun/long/5FunTester
INFO->
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
> {
> ① . "rt":7,
> ① . "total":25,
> ① . "qps":710.2272727272727,
> ① . "excuteTotal":25,
> ① . "failRate":0.0,
> ① . "threads":5,
> ① . "startTime":"2020-02-24 18:27:57",
> ① . "endTime":"2020-02-24 18:27:57",
> ① . "errorRate":0.0,
> ① . "table":"",
> ① . "desc":"FunTester"
> }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
INFO->
INFO-> 5

Process finished with exit code 0

通过屡次运行,最后输出依然是​​5​​,说明线程是安全的。线程

  • 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。