Java多线程-----线程安全

什么是线程安全

连个线程同时操作同一个公共资源,容易造成资源错误

加入两个人代表两个线程他俩同时去取钱10元,但是账户只有10元,如果不处理线程安全容易造成两人都能取出来钱; 

一,线程同步

解决线程安全-----加锁

让多个线程先后依次的访问共享资源


1,同步代码块

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

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

  • 实现同步代码块

    • 选中共享资源的代码CTRL+T  然后选中 synchronized
    • //锁对象:必须是一个唯一的对象(同一个地址)锁对象可以是任何对象甚至是字符串
      synchronized(锁对象){
          //...访问共享数据的代码...
      }

  • 对于静态方法建议使用字节码(类名.class对象作为锁对象。
    • public static void test(){
      
          synchronized(类名.class){
      
          }
      }
  • 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象。
    • this 代表着是共享账户
      public void test(){
      
          synchronized(this){
      
          }
      }

 2,同步方法

将处理共享资源的方法上加上 syschronized 关键字 表示当前是一个同步方法

public synchronized void drawMoney(double money) {
    // 先搞清楚是谁来取钱?
    String name = Thread.currentThread().getName();
    // 1、判断余额是否足够
    if(this.money >= money){
        System.out.println(name + "来取钱" + money + "成功!");
        this.money -= money;
        System.out.println(name + "来取钱后,余额剩余:" + this.money);
    }else {
        System.out.println(name + "来取钱:余额不足~");
    }
}
  • 如果是实例方法默认使用this作为锁对象
  • 如果是静态方法默认使用类名.class作为锁对象
  • 底层原理:
    • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码

同步代码块和同步方法的区别

范围上:同步代码块锁的范围更小,同步方法锁的范围更大

可读性:同步方法更好

3,Lock锁 

  • 怎么实现

    • 创建锁对象,放在方法外面,表示这个是当前对象的锁  加上final修饰表示当前锁无法被修改
      // 创建了一个锁对象
      private final Lock lk = new ReentrantLock();
    • 在方法内部需要加锁的地方加锁
    • 在需要的地方进行解锁
    • 以上两步一般使用try-catch-finally修饰,以防中间代码出现问题也能进行解锁

实现Lock锁

// 创建了一个锁对象
private final Lock lk = new ReentrantLock();

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

注意: 

同一个锁对象可以跨方法锁住多个方法

你可能感兴趣的:(java,jvm,开发语言)