JAVA JVM 层面的锁

发布时间 2023-06-16 20:06:21作者: ayiZzzz

JVM 锁

1、JAVA 为了实现在多线程环境灰姑娘下的线程安全,提供了诸如 synchronized , ReentrantLock 等工具类来解决我们在多线程环境下的线程安全问题。

synchronized 锁

1、上面是 synchronized锁
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

线程不安全的实例

public class UnSafeExample {

    // frequency
    private static final int FREQUENCY = 20;

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(Performance.INSTANCE , "thread-1");
        Thread thread1 = new Thread(Performance.INSTANCE , "thread-2");
        thread.start();
        thread1.start();

        try {
            // 等待两个线程都运行结束后,再打印结果
            thread.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Performance.INSTANCE.cnt);

    }

    enum Performance implements Runnable {

        INSTANCE;

        int cnt = 0;

        @Override
        public void run() {
            for (int i = 0 ; i < FREQUENCY ; ++i) {
                cnt ++ ;
            }
        }
    }
    
}

1、我们通过 Thread开启了两个线程每个线程的run方法执行 20 次cnt ++ 操作,但是实际上当两个线程执行完之后我们发现assertEquals(cnt , 40)等于false2、在并发环境下cnt ++这个操作并不是一个原子性操作,他包含三条指令:读值、+1、写值 3、通过join方法我们可以实现对thread1thread2线程的阻塞等价于countdownlatch`

synchronized 锁的使用

public class SafeExample {

    // frequency
    private static final int FREQUENCY = 20;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(Performance.INSTANCE , "thread-1");
        Thread thread1 = new Thread(Performance.INSTANCE , "thread-2");
        thread.start();
        thread1.start();

        // 模拟延迟
        Thread.sleep(100);
        System.out.println(Performance.INSTANCE.cnt);
    }

     enum Performance implements Runnable {

        // 单例对象
        INSTANCE;

         /**
          *  1、使用枚举类 INSTANCE 设计单例模式
          *  2、使用 volatile 对属性进行修饰---确保多线程环境下的可见性
          */
         volatile int cnt = 0;

        @Override
        public synchronized void run() {
            for (int i = 0 ; i < FREQUENCY ; ++i) {
                cnt ++ ;
            }
        }
    }

}

1、synchronized 修饰方法锁的是当前对象
2、synchronized 修饰代码块锁的是 synchronized(this) 对象
3、synchronized 所锁的是 Class 对象相当于多个该对象的实例
4、volatile 关键字保证了属性的可见性