• 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

    在这里插入图片描述

  • 相关阅读:
    springboot:修改SpringBoot启动图案
    【分享】集简云小程序识别财务票据同步到金蝶云星辰流程搭建示例
    AIRIOT亮相IOTE2023深圳物联网展,产品创新力再获“IOTE金奖”
    腾讯推出首个互联网大厂养老方案
    Docker安装Rabbitmq并挂载宿主机数据目录
    Apache Hive之数据查询
    【Django】Django自定义后台表单——对一个关联外键对象同时添加多个内容
    简道云出现问题及解决方法1
    Win11用户名和密码备份方法
    Centos 7 更改 Mysql 5.7 默认数据库存储路径
  • 原文地址:https://blog.csdn.net/N16696796429/article/details/133840690