关于Arraylist集合线程不安全问题的解决和测试过程出现的问题
解决线程不安全问题
import java.util.ArrayList;
/**
* @Auther Oonday
* @Date 2021-01-22 15:35
*/
public class unsafelist {
public static void main(String[] args) throws InterruptedException {
ArrayList list = new ArrayList();
for (int i = 0; i <= 1000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
//这样就解决了Arrylist不安全问题,那么原来是什么呢?还有测试过程出现的问题
}
}
解决Arraylist不安全问题的原理
1.使用的方法:使用同步代码块来解决线程不安全的问题,这这里最难的就是如何选择那个对象作为同步代码块所需要的锁,我们只要选择需要被多个线程增删改的对象作为锁,这里我们时list集合。
2.出现不安全的原因:上面的代码是 ,所有的线程都要去往list里面添加内容,如果此时,好几个线程都访问list的同一个位置,那么这时候就会导致前一个添加到此位置的内容被覆盖,所以在输出list的大小时i,会出现不是1001个,而是小于这个数。我们知道,线程的执行是靠cpu来调度的,所以并不是等到该线程执行完才会继续执行其他,有可能刚好要执行该位置时,另外一条线程夺得cpu使用权,以知道添加这个位置,然后两个就接连添加到这个地方,所以会存在上面那种同时访问一个位置的情况。
3.解决的原理:同步代码块是一种锁机制,传递一个对象给它,这个对象是所有需要访问到的线程公用的对象,当一个线程获取到此对象的锁并锁住,其他线程执行到这里时,发现,对象被锁住了,所以只能挂起状态(阻塞状态),等待该线程执行完同步内容,然后该线程释放锁,其他对象才一起争夺锁的使用权。这样就实现安全的线程。
测试过程中出现的问题
// System.out.println(list.size());
直接在主线程中输出这个list的大小,发现并没有解决同步问题,其实并不是没有解决,而是,线程安全问题已经解决了,但是,由于主线程获取到执行权,然后提前输出了结果,导致大小并不是应该有的大小。
Thread.sleep(1000);
让主线程睡眠一会,这样,就能让结果正确显示为1001.延长主线程结束的时间。
为了进一步验证,在主线程后面添加上一下代码测试。
// for (int i = 0; i < 1000; i++) {
// System.out.println(list.size()+"->"+list.get(i+1));
// }
发现输出真的时1001个的线程名字,证明我们的同步确实时解决了的。
注;文章同步到公众号:我也是一名新手,有兴趣的小伙伴可以来一起学习哦,加油!