Java线程安全

鳄鱼君

发表文章数:643

热门标签

,

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Java » Java线程安全

当多线程并发的环境下,有共享数据,并且这个数据还会被修改,此时就会存在线程安全问题。要解决线程安全,需要让线程排队执行,不能并发,也被称为线程同步机制。线程同步就是线程排队,线程排队就会牺牲一部分效率,但是数据安全了,如果数据不安全就没有效率的说法。

异步编程模型:线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1,谁也不需要等谁,这种编程模型叫做异步编程
同步编程模型:线程t1和线程t2,在线程t2执行的时候,必须等待t1线程执行结束,两个线程直之间发生了等待关系,这就是同步编程模型

// 不使用线程同步,多线程对同一个账户进行取款,出现问题
public class SafeThreadTest {
    public static void main(String[] args) {
        // 创建账户对象
        Account a1 = new Account("user1",10000);
        // 创建2个线程
        Thread t1 = new AccountThread(a1);
        Thread t2 = new AccountThread(a1);
        // 设置name
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        t2.start();

    }
}
class AccountThread extends Thread{
    // 两个线程必须共享同一个账户对象
    private Account act;
    // 通过构造方法传递账户对象
    public AccountThread(Account act){
        this.act = act;
    }
    public void run(){
        // run方法的执行表示取款
        // 假设取款5000
        double money = 5000;
        act.withdraw(money);
        System.out.println( Thread.currentThread().getName()+"线程"+ act.getActno() + "取款成功,余额:" + act.getBalance());
    }

}
class Account{
    // 账号
    private String actno;
    // 余额
    private double balance;

    public Account(String actno, double balance) {
        this.actno = actno;
        this.balance = balance;
    }

    public Account() {
    }

    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(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 更新数据
        // t1执行到这里,还没有更新数据,t2线程进来执行withdraw,此时就会出问题
        this.setBalance(after);

    }
}

使用线程同步:

// 取款
public void withdraw(double money){
    // 必须线程排队执行,不能并发
    // 一个线程执行结束,下一个线程才能开始

    // 线程同步代码块, 小括号内必须是多线程共享的数据
    // 这里的共享对象是Account
    synchronized (this){
        double before = this.getBalance();
        double after = before - money;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.setBalance(after);
    }
}

synchronized也可以写在实例方法上:

// 实例方法上,锁的是this,不能是其它对象,表示整个方法体都需要同步
// 扩大了同步的范围,程序的效率可能较低
public synchronized void withdraw(double money){
    double before = this.getBalance();
    double after = before - money;
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    this.setBalance(after);

}

在java语言中,任何一个对象都有一把锁,这把锁就是标记,100个对象100把锁,1个对象1把锁。

Java中有三大变量:实例变量(堆中)、静态变量(方法区)、局部变量(栈中)。局部变量永远都不会存在线程安全问题,因为局部变量不共享,一个线程一个栈。堆和方法区都是多线程共享,所以可能会发生线程安全

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《Java线程安全》 发布于2020-08-18

分享到:
赞(0) 赏杯咖啡

评论 抢沙发

7 + 2 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册