线程安全问题

目录

 1.什么是线程安全问题 ?

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

解决方法一:同步代码块

  作用: 把访问共享资源的核心代码给上锁,以此保证线程安全

解决方法二:同步方法

           作用:把访问共享资源的核心方法给上锁,以此保证线程安全

解决方法三:创建锁对象

 作用:可以在指定位置处加锁,解锁,更灵活


 1.什么是线程安全问题 ?

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

场景: 小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元,
如果小明和小红同时来取钱,并且2人各自都在取钱10万元,可能会出现什么问题呢?

解决方法一:同步代码块


  作用: 把访问共享资源的核心代码给上锁,以此保证线程安全


synchronized(同心锁){
    访问共享资源的核心代码
}


原理: 每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行


同步锁的注意事项:对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug

锁对象的使用规范:
建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象
对于静态方法建议使用字节码(类名.class)对象作为锁对象

 public void drawMoney(double money) {
        // 同步代码块

        // 先搞清楚是谁来取钱
        String name=Thread.currentThread().getName();
        synchronized (this){
        // 判断余额是否足够?
        if (this.getMoney()>=money){
            System.out.println(name+"取钱成功"+money);
            // 更新余额
            this.money-=money;
            System.out.println(name+"来取钱成功后剩余"+this.money);
        }
        else {
            System.out.println("余额不够哦");
        }
    }
    }

解决方法二:同步方法


作用:把访问共享资源的核心方法给上锁以此保证线程安全


修饰符 synchronized 返回值类型 方法名称 (){
            操作共享资源的代码
}


原理:每次只能进入一个线程进去,进去后会上锁,出来后会自动解锁,同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码


如果方法是实例方法:同步方法默认用this作为的锁对象
如果方法是静态方法:同步方法默认用类名.class作为的锁对象

     是同步代码块好还是同步方法好一点?
范围上 : 同步代码块锁的范围更小,同步方法锁的范围更大
可读性: 同步方法更好

 // 同步方法
    public synchronized void drawMoney(double money) {

        // 先搞清楚是谁来取钱
        String name=Thread.currentThread().getName();

        // 判断余额是否足够?
        if (this.getMoney()>=money){
            System.out.println(name+"取钱成功"+money);
            // 更新余额
            this.money-=money;
            System.out.println(name+"来取钱成功后剩余"+this.money);
        }
        else {
            System.out.println("余额不够哦");
        }

    }

解决方法三:创建锁对象

作用:可以在指定位置处加锁,解锁,更灵活

final private Lock lk =new ReentrantLock();

lk.lock(); // 加锁

lk.unlock(); // 解锁   一般会放在try...catch finally里

    public  void drawMoney(double money) {

        // 先搞清楚是谁来取钱
        String name=Thread.currentThread().getName();
        lk.lock(); // 加锁
        // 判断余额是否足够?
        try {
            if (this.getMoney()>=money){
                System.out.println(name+"取钱成功"+money);
                // 更新余额
                this.money-=money;
                System.out.println(name+"来取钱成功后剩余"+this.money);
            }
            else {
                System.out.println("余额不够哦");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            lk.unlock(); // 解锁
        }

    }

你可能感兴趣的:(jvm)