目录
1.成员变量---int类型的成员变量number 线程共享,会有并发
3.成员变量---int /string类型的数组 线程共享,会有并发
5.成员变量---HashMap 线程共享,会有并发,string>
6.成员变量---自己创建的实体类(多例模式) 线程共享,会有并发
7.成员变量---自己创建的实体类(单例模式) 线程共享,会有并发
4.局部变量---ArrayList 线程不共享,不存在并发
5.局部变量---HashMap 线程不共享,不存在并发,string>
6.局部变量---自己创建的实体类(多例模式) 线程不共享,不存在并发
7.局部变量---自己创建的实体类(单例模式) 线程共享,存在并发
@autowired注入的自己创建的实体类 是单例模式,线程共享一个对象
成员变量
前提条件,把这个stu类设成是单例模式,也就是说,这个类只能创建一个对象,然后多个线程在一个对象中去争抢资源.
1.成员变量---int类型的成员变量number 线程共享,会有并发
public class Stu {
private Nat nat =new Nat();
private int number;
private String name = "你好";
private HashMap<String, String> map = new HashMap<>();
private ArrayList<String> list = new ArrayList<>();
private String[] shuzu = {"你", "好"};
public void aa() {
number=number+1;
System.out.println(Thread.currentThread().getName() + " 值 " + number + " stu内存 " + System.identityHashCode(number));
}
@Component
public class MyRunnable implements Runnable{
@Override
public void run(){
Stu stu = Stu.getInstance();
stu.aa();
}
}
public class testb {
public static void main(String[] args) {
//创建线程池
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
pool.submit(new MyRunnable());
}
pool.shutdown();
}
}
创建10个线程去执行stu对象的成员变量的number++;
下图是结果:
打印的int类型的成员变量的值一样内存地址一样,值不一样,内存地址就不一样.
打印的结果混乱且叠加,证明多线程争抢,发生了并发.
2.成员变量---string类型 线程共享,会有并发
创建10个线程去获得单例对象stu内的成员变量string name, 让10个线程都去改变string name的值,然后打印最后string name的值,和每个线程执行到的string name的内存
结果显示,10个线程去改变值后的string name的内存是值相同的内存一样,值不相同的内存不一样.
结果是混乱的,证明有并发的现象出现,就是发生了并发.
3.成员变量---int /string类型的数组 线程共享,会有并发
创建10个线程去获得单例对象stu内的成员变量int[] shuzu, 让10个线程都去对数组减一操作,然后打印最后数组的元素的值,和每个线程执行到的数组的内存
下面是结果:
结果显示,10个线程创建的数组的内存都是一样的,证明这个成员变量的数组是线程共享的,一个线程new出来一个数组后,那么其他数组就共享使用这个数组了.
而每个线程都去减一后,打印的结果很乱有重复,证明有并发的现象出现,就是发生了并发.
4.成员变量---ArrayList<interger/String> 线程共享,会有并发
创建10个线程去获得单例对象stu内的成员变量ArrayList<interger> , 让10个线程都去对集合添加一个1元素,然后打印最后集合的值,和每个线程执行到的集合的内存
下面是结果:
结果显示,10个线程创建的ArrayList集合的内存都是一样的,证明这个成员变量的集合是线程共享的,一个线程new出来一个集合后,那么其他数组就共享使用这个集合了.
而每个线程都去对集合添加1元素后,打印的结果有null出现,证明有并发的现象出现,就是发生了并发.
5.成员变量---HashMap<string,string> 线程共享,会有并发
创建10个线程去获得单例对象stu内的成员变量hashmap<string,string> , 让10个线程都去对hashmap添加一个键值对,然后打印最后hashmap的值,和每个线程执行到的hashmap的内存
下面是结果:
结果显示,10个线程创建的hashmap<string,string>的内存都是一样的,证明这个成员变量的hashmap是线程共享的,一个线程new出来一个hashmap后,那么其他线程就共享使用这个hashmap了.
而每个线程都去对集合hashmap添加一个键值对,打印的结果最后是第3个线程的,证明有并发的现象出现,就是发生了并发.
6.成员变量---自己创建的实体类(多例模式) 线程共享,会有并发
创建10个线程去执行单例对象stu内成员方法aa() , 然后输出成员变量实体类nat内的元素值和nat的内存地址.
下面是结果:
结果显示,10个线程创建的实体类nat的内存是一样的,证明这个成员变量的实体类nat是线程共享的.一个线程new出来,其他线程共用.
而每个线程都去对实体类nat中的元素进行加1操作,打印的结果是混乱叠加的,证明存在并发.
7.成员变量---自己创建的实体类(单例模式) 线程共享,会有并发
创建10个线程去执行单例对象stu内成员方法aa() , 然后输出成员变量实体类nat内的元素值和nat的内存地址.
下面是结果:
结果显示,10个线程创建的实体类nat的内存是一样的,证明这个成员变量的单例模式的实体类nat是线程共享的.一个线程new出来,其他线程共用.
而每个线程都去对实体类nat中的元素进行加1操作,打印的结果是混乱叠加的,证明存在并发.
局部变量
前提条件,把这个stu类设成是单例模式,也就是说,这个类只能创建一个对象,然后多个线程在一个对象中去争抢资源.
1.局部变量-- int类型 线程不共享,不会有并发
创建10个线程去执行stu对象的aa()方法里的局部变量的number++;
下图是结果:
内存地址都是一样的,说明有一个基本类型常量池
结果都是1.证明不存在并发
2.局部变量---string类型 线程不共享,不存在并发
创建10个线程去执行stu对象的aa()方法里的string name +"啊";
结果内存都不一样,证明局部变量sting类型线程不共享.
结果值都是一样的,证明线程没有发生争抢.
3.局部变量-- int类型的数组 线程不共享,不存在并发
创建10个线程去执行单例对象stu的aa()方法, 让这10个数组都去对这个数组减一操作,然后打印最后数组的元素的值,和每个线程执行到的数组的内存
下图是结果
结果证实:每个线程new出的数组的内存地址都不一样... (int [] arr=new int[]{0})这种在成员方法里的局部变量, 每个线程都会自己去new一个数组出来, 会在堆中new出10个地址不同的数组来,然后每个线程执行的时候各找各的new出的数组,所以它们互不影响.
结果证实:每个线程都new了一个自己的数组,因此它们各自减一,得的结果都是9,不存在并发.
所以, 数组作为局部变量,是线程不共享的,是线程安全的.
4.局部变量---ArrayList<interger/String> 线程不共享,不存在并发
创建10个线程去new局部变量ArrayList<interger> , 让10个线程都去对集合添加一个1元素,然后打印最后集合的值,和每个线程执行到的集合的内存
下面是结果:
结果显示,10个线程创建的ArrayList集合的内存是不一样的,证明这个局部变量的集合是线程私有的.
而每个线程都去对集合添加1元素后,打印的结果都为1,证明不存在并发.
5.局部变量---HashMap<string,string> 线程不共享,不存在并发
创建10个线程去new局部变量hashmap<string,string> , 让10个线程都去对hashmap添加一个键值对,然后打印最后hashmap的值,和每个线程执行到的hashmap的内存
下面是结果:
结果显示,10个线程创建的hashmap<string,string>的内存是不一样的,证明这个局部变量的hashmap是线程私有的.
而每个线程都去对hashmap添加一个键值对后,打印的结果互不影响,证明不存在并发.
6.局部变量---自己创建的实体类(多例模式) 线程不共享,不存在并发
创建10个线程去执行单例对象stu内成员方法aa() , 然后输出局部变量实体类nat内的元素值和nat的内存地址.
下面是结果:
结果显示,10个线程创建的实体类nat的内存是不一样的,证明这个局部变量的多例模式实体类nat是线程私有的.
而每个线程都去对实体类nat中的元素进行加1操作,打印的结果都是1,证明不存在并发.
7.局部变量---自己创建的实体类(单例模式) 线程共享,存在并发
创建10个线程去执行单例对象stu内成员方法aa() , 然后输出局部变量实体类nat内的元素值和nat的内存地址.
下面是结果:
结果显示,10个线程创建的单例模式实体类nat的内存是一样的,证明这个局部变量的单例模式实体类nat可以看做是线程共享一个nat对象的.
而每个线程都去对实体类nat中的元素进行加1操作,打印的结果是有重复合混乱的,证明存在并发.
@autowired注入的自己创建的实体类 是单例模式,线程共享一个对象
用apifox发起5次并发请求. 将自己创建的实体类stu用@autowired注解注入到类中,输入实体类stu的内存地址,和执行stu内的aa()方法.
下面是结果:
结果显示,前端发起的5次并发请求,创建的stu的对象的内存地址都是一样的,这样就证明了用@autowired注入的对象是单例对象,也证明了spring默认创建的是单例对象.所以就是5个线程共用了一个stu对象.
而每个线程都去对成员变量string[]数组进行加"啊"操作,打印的结果是混乱叠加的,证明存在并发.
而每个线程都去对局部变量string[]数组进行加"啊"操作,打印的结果是互不影响的,证明没有并发.
用static 修饰的成员变量和局部变量对并发会有影响吗?
首先,static不能修饰局部变量,会编译报错,
其次,用static修饰的成员变量在并发方面一点影响和作用都没有.
用final修饰的常量对并发会有影响吗?
用final修饰成员变量-基本类型,有影响,因为基本类型成了个常量,后面没有代码对其进行修改值,因此就没有了并发问题. 由并发变成了没并发
用final修饰成员变量-对象类型,对并发结果没有任何影响 照样有并发
用final修饰局部变量-基本类型, 对并发结果没有任何影响 照样没并发
用final修饰局部变量-对象类型,对并发结果没有任何影响 照样没并发