一 什么是多线程环境下的数据安全问题
多线程环境下的数据安全问题需要满足三个条件
- 多线程并发
- 多个线程有共享数据
- 被共享的数据有修改的行为
二 多线程环境下数据安全的重要性
- 以后在实际的开发中,我们的项目都是运行在服务器上,而服务器已经将线程的定义、线程对象的创建、线程的启动等都已经实现完了。这些代码我们不需要编写。
- 最重要的是我们需要知道,我们编写的程序要放到一个多线程的环境下运行,我们更需要关注的是这些数据在多线程的环境下是否是安全的。
存在线程安全的案例
三 怎么解决线程安全问题呢?
使用"线程同步机制",实际上就是线程不能并发了,线程需要排队执行。
线程同步会牺牲一部分效率,数据安全是第一位的,如果数据都不安全,那效率也就没有意义了。
1. 线程同步涉及到的两个专业术语
- 异步编程模型:线程t1和线程t2,各自执行各自的,t1不管t2,t2也不管t1,谁也不需要等谁,这种编程模型就是异步编程模型
- 同步编程模型:线程t1和线程t2,当线程t1要执行的时候,必须等线程t2执行结束,线程t2要执行的时候,也要等t1执行结束,两个线程发生了等待关系,这就是同步编程模型
2. 哪些变量会出现线程安全问题
- 实例变量:存在于堆内存中,堆内存只有一个,有线程安全问题
- 静态变量:存在于方法区内存中,方法区内存只有一个,有线程安全问题
- 局部变量:存在于栈内存中,每个线程都有自己的栈,局部变量不会被共享,所以没有线程安全问题
3. 案例说明synchronized关键字解决线程安全问题
下面这个案例模拟的是银行取款操作,如果不加synchronized关键字进行同步操作的话,那么可能会出现问题:账户余额不合理的情况。加了synchronized关键字,表示的是同步一段代码块,并且提供了一个多线程共享的实例变量以加锁,就不会出现线程安全的问题了,当然在此处代码中取款操作没有比较余额和取款值的大小,并不严谨。
public class Account {
private String actno;
private double balance;
public Account(String actno, double balance) {
this.actno = actno;
this.balance = balance;
}
public void withdraw(double money) {
//在这个位置传的引用类型的变量时至关重要的!!!!!
synchronized (this) {
double before = this.getBalance();// 获取最初的余额
double after = before - money;// 计算最新余额
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace()