• Java多线程悲观锁和乐观锁


    悲观锁:
    一上来就加锁,没有安全感,每次只能一个线程进入访问完毕后,再解锁。 线程安全,性能较差

    乐观锁:
    一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。 线程安全,性能较好

    接下来我们通过案例,来分别实现三种情况:1、不加锁的情况,2、加悲观锁 3、加乐观锁。我们创建两个类来进行案例的演示,分别是Test类MyRunnable类。

    1、不加锁的情况

    MyRunnable类

    package ThreadTzTest;
    
    public class MyRunnable implements Runnable{
        private int count;//记录浏览人数
        @Override
        public  void run() {
            //100次
                for (int i = 0; i < 100; i++) {
                    System.out.println("count======>"+(++count));
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Test类

    package ThreadTzTest;
    
    public class Test {
        public static void main(String[] args) {
            //目标:拓展悲观锁、乐观锁原理
            //悲观锁:一上来就加锁,没有安全感,每次只能一个线程进入访问完毕后,再解锁。     线程安全,性能较差
            //乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。   线程安全,性能较好
    
    
            //需求:1个静态变量,100个线程,每个线程对其加100次
            Runnable target = new MyRunnable();
    
            for (int i = 1; i <= 100; i++) {
                new Thread(target).start();
    
                
            }
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    运行结果:
    在这里插入图片描述
    可以看到结果是不正确的,正确结果应该是10000,这是因为出现了线程安全问题。

    2、添加悲观锁

    MyRunnable类

    package ThreadTzTest;
    
    public class MyRunnable implements Runnable{
        private int count;//记录浏览人数
        @Override
        public  void run() {
            //100次
            synchronized (this) {
                for (int i = 0; i < 100; i++) {
                    System.out.println("count======>"+(++count));
                }
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Test类不变,我们再来看运行结果:
    在这里插入图片描述
    可以看到,添加悲观锁后线程正确运行了,没有出现线程安全问题。

    3、添加乐观锁

    package ThreadTzTest;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class MyRunnable2 implements Runnable{
        //整数修改的乐观锁,原子类实现的
        private AtomicInteger count = new AtomicInteger();
    
    
        @Override
        public  void run() {
            //100次
                for (int i = 0; i < 100; i++) {
                    System.out.println("count======>"+count.incrementAndGet());
                    //incrementAndGet()先加1再返回,在方法的内部没有加锁
    
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    package ThreadTzTest;
    
    public class Test {
        public static void main(String[] args) {
            //目标:拓展悲观锁、乐观锁原理
            //悲观锁:一上来就加锁,没有安全感,每次只能一个线程进入访问完毕后,再解锁。     线程安全,性能较差
            //乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。   线程安全,性能较好
    
    
            //需求:1个静态变量,100个线程,每个线程对其加100次
            Runnable target = new MyRunnable2();
    
            for (int i = 1; i <= 100; i++) {
                new Thread(target).start();
    
                
            }
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    运行结果:
    在这里插入图片描述
    乐观锁实现原理:

    先存下原来的值是多少,然后进行数据的操作,进行修改的时候判断存下来的值和现在的值是否相等,如果相等就把修改后的数据存进去

    4、乐观锁案例

    在这里插入图片描述

    public class OptimisticLock {  
        private int version;  
        private String data;  
      
        public String readData() {  
            return data;  
        }  
      
        public boolean updateData(String newData) {  
            int currentVersion = version;  
            // 更新数据  
            data = newData;  
            version++;  
            // 检查版本号是否一致  
            if (currentVersion != version) {  
                // 版本号不一致,回滚事务  
                return false;  
            }  
            // 提交事务  
            return true;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

  • 相关阅读:
    从0备战蓝桥杯:找出只出现一次的数字,数单身狗
    00、数组及字符串常用的 API(详细剖析)
    PDF文件压缩软件 PDF Squeezer mac中文版​软件特点
    霍格沃兹~~~
    SpringBoot项目中Interceptor拦截器中使用@Autowired注解,运行时会报错空指针
    Android——SRT字幕文件的下载、解压、转换、显示
    JUC P3 共享模型之无锁同步,CAS,原子类,Unsafe类 基础+代码
    HTML+CSS大作业 (水果之家10个网页)
    Python trino执行hive insert overwrite不生效的问题
    基于.Net Core实现的飞书所有文档一键导出服务(支持多系统)
  • 原文地址:https://blog.csdn.net/N16696796429/article/details/133840690