JAVA中的多线程并发环境下数据的安全问题(概述)
-
为什么这个是重点?
以后在开发中,我们的项目都是运行在服务器当中,而服务器已经将线程的定义,
线程对象的创建,线程的启动等,都已经实现完了,这些代码我们不需要编写。
最重要的是,你要知道,编写的程序需要放到一个多线程的环境下运行,你更需要
关注的是这些数据在多线程并发的环境下是否安全。(重点!!!!!!) -
什么时候数据在多线程并发的环境下会存在安全隐患?
三个条件:
条件1:多线程并发
条件2:有共享数据
条件3:共享数据有修改的行为
满足以上三个条件,就会存在线程安全问题 -
怎么解决线程安全问题:
当多线程并发的环境下,有共享数据,并且这个数据还会被修改,此时就存在线程
安全问题,该如何解决:
线程排队执行(不能并发)
用排队执行解决线程安全问题
这种机制被称为:线程同步机制
实际上就是线程不能并发了,线程必须排队执行,会牺牲一部分效率。
只有数据安全了,效率才有意义 -
线程同步:
1、异步编程模型:
线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1,
也就是“多线程并发”(效率较高)
2、同步编程模型:
线程t1和线程t2,在线程t1执行的时候,必须等待t2线程执行结束,或者线程t2
执行的时候,必须等待t1线程执行结束,两个线程之间发生了等待关系。
效率较低。 -
Java中有三大变量:
1、实例变量:在堆中2、静态变量:在方法区中
3、局部变量:在栈中
以上三大变量中:
局部变量和常量永远不会存在线程安全问题,因为局部变量不共享(一个线程一个栈)
实例变量在堆中,堆只有一个,
静态变量在方法区中,方法区只有一个
堆和方法区都是多线程共享的,所以可能存在线程安全问题 -
StringBuilder和StringBuffer
如果使用局部变量的话:
建议使用StringBuilder
因为局部变量不存在线程安全问题,使用StringBuilder效率更高ArrayList是非线程安全的
Vector是线程安全的
HashSet和HashMap是非线程安全的
Hashtable是线程安全的 -
总结:
synchronized三种写法:
第一种:同步代码块(灵活)
synchronized(线程共享对象){
同步代码块
}
第二种:在实例方法上使用synchronized
表示共享对象一定是this
并且同步代码块是整个方法体
第三种:在静态方法上使用synchronized
表示找类锁
类锁永远只有一把
就算创建了100个对象,也只有一把类锁
对象锁:1个对象1把锁
类锁:对象再多,也只有一把锁 -
以后的开发中如何解决线程安全问题:
是一上来就synchronized线程同步吗?
不是,synchronized会让程序的执行效率降低,用户体验不好,系统的用户吞吐量
降低,用户体验差,在不得已的情况下再选择线程同步机制
第一种方案:尽量使用“局部变量”代替“实例变量”和“局部变量”。
第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样实例变量的内存
就不共享了,(1个线程对应1个对象,100个线程对应100个对象,对象不共享,
就没有数据安全问题了)第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候就只能选择
synchronized线程同步机制了。