Java线程安全的案例及实现

Java线程安全的案例及实现,第1张

Java线程安全的案例及实现

笔记

线程安全问题:多个线程同时 *** 作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题

例如下面这段代码

public class Account {
    private String id;
    private double money;

    public Account() {
    }

    public Account(String id, double money) {
        this.id = id;
        this.money = money;
    }
    public void DrawMoney(double money) {
        String name= Thread.currentThread().getName();
        if (this.money>=money){
            System.out.println(name+"取钱成功,吐出"+money);
            this.money-=money;
            System.out.println("余额"+this.money);
        }else {
            System.out.println(name+"来取钱,余额不足");
        }
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public String getId() {
        return id;
    }

    public double getMoney() {
        return money;
    }
}
public class MyThread extends Thread{
    private Account acc;
    public MyThread(String name,Account acc){
        super(name);
        this.acc=acc;
    }
    @Override
    public void run() {
        acc.DrawMoney(100000);
    }
}
public class Test {
    public static void main(String[] args) {
        Account account=new Account("1314",100000);

        new MyThread("小明",account).start();
        new MyThread("小红",account).start();
    }
}

账户内只有100000元,当两个人同时取钱时,若小明取完钱,账户内的余额还未更新,小红又取了钱,那么此时两人都取了100000元(血赚),为了防止这种问题出现,就有了线程安全。那么如何实现线程安全呢。

1、synchronized同步代码块

   public void DrawMoney(double money) {
        String name=Thread.currentThread().getName();
        //同步代码块
        synchronized (this){
        if (this.money>=money){
            System.out.println(name+"取钱成功,吐出"+money);
            this.money-=money;
            System.out.println("余额"+this.money);
        }else {
            System.out.println(name+"来取钱,余额不足");
       }
    }}

 这里对出现的问题核心代码使用synchronized进行加锁 ,每次只能有一个线程占锁进行访问,此时就实现了线程安全。

锁对象的要求:1、对于实例方法建议使用this做为锁对象

                         2、对于静态方法建议使用字节码(类名.class)对象做为锁对象

2、使用synchronized修饰方法

    public synchronized void DrawMoney(double money) {
        String name= Thread.currentThread().getName();
        if (this.money>=money){
            System.out.println(name+"取钱成功,吐出"+money);
            this.money-=money;
            System.out.println("余额"+this.money);
        }else {
            System.out.println(name+"来取钱,余额不足");
        }
    }

这种方法比同步代码快简约,但性能比同步代码块差一点,程序员可根据不同的使用场景进行选择运用。

3、创建锁对象的方法(这种方法很专业)

这里只展示账户类的代码,测试类和线程类和第一个代码段一样

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Account {
    private String id;
    private double money;
    private final Lock lock=new ReentrantLock();
//锁对象用final修饰,唯一且不可替换,非常专业
    public Account() {
    }

    public Account(String id, double money) {
        this.id = id;
        this.money = money;
    }

    public void DrawMoney(double money) {
        String name=Thread.currentThread().getName();
        lock.lock();//上锁
        try{
        if (this.money>=money){
            System.out.println(name+"取钱成功,吐出"+money);
            this.money-=money;
            System.out.println("余额"+this.money);
        }else {
            System.out.println(name+"来取钱,余额不足");
        }}finally {
            lock.unlock();//解锁
        }
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public String getId() {
        return id;
    }

    public double getMoney() {
        return money;
    }
}

总结:以上就是线程安全的三种实现方法

线程安全问题出现的原因:存在多线程并发;同时访问共享资源;同时修改共享资源。

笔记结束

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5716336.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存