java线程安全问题详解
Posted 我想月薪过万
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程安全问题详解相关的知识,希望对你有一定的参考价值。
一、什么时候数据在多线程并发的环境下会存在安全问题?
三个条件:
- 条件1:多线程并发。
- 条件2:有共享数据。
- 条件3:共享数据有修改的行为。
满足以上3个条件之后,就会存在线程安全问题。
二、怎么解决线程安全问题?
线程排队执行。(不能并发)。用排队执行解决线程安全问题。这种机制被称为:线程同步机制。
三、银行 取钱/存钱 案例
Account 类
package ThreadSafa;
/*
银行账户
*/
public class Account
// 账号
private String actno;
// 余额
private double balance;
public Account()
public Account(String actno, double balance)
this.actno = actno;
this.balance = balance;
public String getActno()
return actno;
public void setActno(String actno)
this.actno = actno;
public double getBalance()
return balance;
public void setBalance(double balance)
this.balance = balance;
//取款方法
public void withdraw(double money)
// 取款之前的余额
double before = this.getBalance();
// 取款之后的余额
double after = before - money;
// 更新余额
try
//模拟网络延时 更新余额不及时 百分百会出问题
Thread.sleep(1 * 1000);
catch (InterruptedException e)
e.printStackTrace();
this.setBalance(after);
AccountThread 类
package ThreadSafa;
public class AccountThread extends Thread
// 两个线程必须共享同一个账户对象。
private Account act;
//通过构造方法传递过来账户对象
public AccountThread(Account act)
this.act = act;
@Override
public void run()
double money = 5000;
//取款
act.withdraw(5000);
System.out.println(Thread.currentThread().getName() + "账户" + act.getActno() + "取款成功,余额" + act.getBalance());
Test 类
package ThreadSafa;
public class Test
public static void main(String[] args)
// 创建账户对象
Account act = new Account("act-001", 10000);
//创建两个线程
Thread t1 = new AccountThread(act);
Thread t2 = new AccountThread(act);
//设置name
t1.setName("t1");
t2.setName("t2");
//启动线程
t1.start();
t2.start();
运行问题
解决方法 修改 Account 类 中的 withdraw 方法
package ThreadSafa;
/*
银行账户
*/
public class Account
// 账号
private String actno;
// 余额
private double balance;
public Account()
public Account(String actno, double balance)
this.actno = actno;
this.balance = balance;
public String getActno()
return actno;
public void setActno(String actno)
this.actno = actno;
public double getBalance()
return balance;
public void setBalance(double balance)
this.balance = balance;
//取款方法
public void withdraw(double money)
// 以下这几行代码必须是线程排队的,不能并发
// 一个线程把这里的代码全部执行结束之后,另外一个线程才能进来
/*
线程同步机制的语法是:
synchronized ()
// 线程同步代码块
synchronized后面小括号中的这个“数据”是相当关键的。
这个数据必须是多线程共享的数据。才能达到多线程排队
()中写什么?
那要看你想让那些线程同步。
假设t1、t2、t3、t4、t5,有5个线程,
你只希望t1 t2 t3排队,t4 t5 不需要排队。怎么办?
你一定要在()中写一个t1 t2 t3共享的对象。而这个
对象对于t4 t5来说不是共享的。
这里的共享对象是:账户对象
账户对象是共享的,那么this就是账户对象吧!!!
不一定是 this ,这里只要是多线程共享的那个对象就行。
*/
synchronized (this)
// 取款之前的余额
double before = this.getBalance();
// 取款之后的余额
double after = before - money;
// 更新余额
try
//模拟网络延时 更新余额不及时 百分百会出问题
Thread.sleep(1 * 1000);
catch (InterruptedException e)
e.printStackTrace();
this.setBalance(after);
四、总结
- 一个对象一把锁
- 线程拿到锁才能执行同步代码块代码
以上是关于java线程安全问题详解的主要内容,如果未能解决你的问题,请参考以下文章