您的位置:首页 > 数据库 > Redis

验证ArrayList线程不安全,redisson提供的分布式集合线程安全

2018-03-22 17:38 781 查看
借鉴这篇文章的测试方法。一。.测试ArrayListpublic class TestList implements Runnable{

//线程不安全
private List threadList = new ArrayList();
//线程安全
//private List threadList = Collections.synchronizedList(new ArrayList());

@Override
public void run() {
try {
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//把当前线程名称加入list中
threadList.add(Thread.currentThread().getName());
}

@Test
public void test() throws InterruptedException{
TestList listThread = new TestList();

for(int i = 0; i < 100; i++){
Thread thread = new Thread(listThread, "线程"+String.valueOf(i)); //线程名是 i
thread.start();
}

//等待子线程执行完
Thread.sleep(2000);

System.out.println(listThread.threadList.size());
//输出list中的值
for(int i = 0; i < listThread.threadList.size(); i++){
//如果元素是null 则换行,元素是null也会在控制台输出
if(listThread.threadList.get(i) == null){
System.out.println();;
}
System.out.print(listThread.threadList.get(i) + " ");
//输出结果是乱的,因为不一定哪个线程先把线程名放进集合
}
}
} 开一百个线程,把线程名加进集合,最后输出,如果集合元素是null 就换行。
输出结果有null或者数组越界异常说明 ArrayList 线程不安全。
原因是,ArrayList 的add方法分两步:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
1.size是当前元素的数量,判断集合大小是否允许再加一个元素,只要能允许再加一个,集合上限就不会增加
2.加一个元素

3.size++
如果线程1 执行完第二步,失去资源,线程2执行,由于size还没有++,线程2 的名称会覆盖集合中线程1 的名称,然后size+1,轮到线程1执行,size又+1.就会导致第二个元素是null。
如果线程1 执行到第一步,判断集合大小 刚好 可以再放下一个元素,暂停轮到 线程2 执行也判断可以加1元素,然后线程2把线程名称加入集合,size+1,线程1再加入元素 就已经越界了。

二。测试redisson 的RList<Object>
结果没有出现null和越界异常,说明RList是线程安全的。 线程安全主要体现在对数据的写,不会出现脏数据public class TestRedisson implements Runnable{

@Autowired
RedissonClient redissonClient;

private RList<Object> list;

@Override
public void run() {
try {
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//把当前线程名称加入list中
list.add(Thread.currentThread().getName());
}

@Test
public void test() throws InterruptedException{
RList<Object> list = redissonClient.getList("list");
TestRedisson t=new TestRedisson();
t.setList(list);

for(int i = 0; i < 1000; i++){
Thread thread = new Thread(t, "线程"+String.valueOf(i)); //线程名是 i
thread.start();
}

//等待子线程执行完
Thread.sleep(2000);

System.out.println(t.getList().size());
//输出list中的值
for(int i = 0; i < t.getList().size(); i++){
//如果元素是null 则换行,元素是null也会在控制台输出
if(t.getList().get(i) == null){
System.out.println();;
}
System.out.print(t.getList().get(i) + " ");
//输出结果是乱的,因为不一定哪个线程先把线程名放进集合
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redisson