先简单介绍一下线程安全,必须发生在多个线程并发执行,若是单个线程发生线程安全的概率低,很多初学者对线程和进程理解不是很清楚,进程可以看作一个应用程序,线程可以看作应用程序的组成部分,多线程的机制可以提高效率,但是会出现共享资源不安全的问题!而在实际开发的时候一般都是两个编程模型(同步模型--线程安全以及异步模型--线程不安全)
下面是不使用线程安全,执行会发生取出的钱与余额不对应,会多取钱,发生线程不安去
package com.java.projecttest;
/*实际开发中更重要的是线程的安全性
*了解线程不安全的条件
多线程并发
有共享数据
共享数据有修改行为
*如何解决线程安全问题 线程排队执行不可并发执行
*这种机制又称线程同步机 优点:安全,缺点:效率低一些
两种编程模型
同步模型
线程排队执行,效率较低
异步编程模型
线程并发,效率高
*/
public class Projecttest08 {
public static void main(String [] agrs) {
//定义线程内部类
class Mythread extends Thread{
private Mymanni act;//账户对象
public Mythread(Mymanni act) {
super();
this.act = act;
}
public void run() {
//取款5000
double money=10000;
act.getruch(money);
System.out.println("线程"+Thread.currentThread()+"对账户取款成功!余额还有"+act.getBalance());
}
}
//创建卡
Mymanni a=new Mymanni("action--1",10000);
//模拟两个线程
Thread t1=new Mythread(a);
Thread t2=new Mythread(a);
t1.setName("t1");
t2.setName("t2");
//启动
t1.start();
t2.start();
}
}
//定义账户类
class Mymanni{
private String id;//卡号
private double balance;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public Mymanni(String id, double balance) {
super();
this.id = id;
this.balance = balance;
}
//取款方法
public void getruch(double money) {
//取款前
double before=this.getBalance();
//取款后
double after=before-money;
//更新
this.setBalance(after);
}
}
运行结果
分析看出,我取了10000,但是卡里的余额还有5000,而卡里只有10000,发生线程不安全,多取钱的小编就得去蹲号了
下面是使用线程安全机制(synchronized)
package com.java.projecttest;
/*线程同步机制解决线程安全问题*/
public class Projecttest08 {
public static void main(String [] agrs) {
//定义线程内部类
class Mythread extends Thread{
private Mymanni act;//账户对象
public Mythread(Mymanni act) {
super();
this.act = act;
}
public void run() {
//取款5000
double money=5000;
act.getruch(money);
System.out.println("线程"+Thread.currentThread()+"取款"+money+"对账户取款成功!余额还有"+act.getBalance());
}
}
//创建卡
Mymanni a1=new Mymanni("action--1",10000);
//模拟两个线程
Thread t1=new Mythread(a1);
Thread t2=new Mythread(a1);
t1.setName("t1");
t2.setName("t2");
//启动
t1.start();
t2.start();
}
}
//定义账户类
class Mymanni{
private String id;//卡号
private double balance;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public Mymanni(String id, double balance) {
super();
this.id = id;
this.balance = balance;
}
//取款方法
public void getruch(double money) {
//这里的代码必须使用线程同步机制
synchronized(this){
//synchronized后面括号写的是线程共享的资源
double before =this.getBalance();
double after=before-money;
try {
Thread.sleep(1000*2);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}//等待时间
this.setBalance(after);
}
}
}
运行结果
可以看出取钱正常,不存在多取钱,小编不用蹲号