zoukankan      html  css  js  c++  java
  • 关于保障线程安全的几种方法,通俗易懂

    原文:https://www.cnblogs.com/lixinjie/p/10817860.html,讲得很通俗易懂。

    我从文中学到的几点(线程安全方面):

      在多线程环境中,存在于堆内存的公共资源可以被很多线程访问,也就存在安全隐患(数据容易被修改)。

      所以,为了保障数据的安全,就要对这些数据做些处理。

    一、从变量上着手:

    方法一:将变量放在方法中,也就是局部变量【操作系统会为每个线程分配属于它自己的内存空间,通常称为栈内存,其它线程无权访问,而局部变量在栈内存中】

    double avgScore(double[] scores) {
        double sum = 0;
        for (double score : scores) {
            sum += score;
        }
        int count = scores.length;
        double avg = sum / count;
        return avg;
    }

    方法二:变量在类中的方法外 ,即成员变量,这时可以利用ThreadLocal【原理:多个线程访问同一共享变量时,ThreadLocal类为每个线程提供一份该变量的副本,各个线程拥有一份属于自己的变量副本,操作修改的是各自的变量副本,而不会相互影响。】

    class StudentAssistant {
    
        ThreadLocal<String> realName = new ThreadLocal<>();
        ThreadLocal<Double> totalScore = new ThreadLocal<>();
    
        String determineDegree() {
            double score = totalScore.get();
            if (score >= 90) {
                return "A";
            }
            if (score >= 80) {
                return "B";
            }
            if (score >= 70) {
                return "C";
            }
            if (score >= 60) {
                return "D";
            }
            return "E";
        }
    
        double determineOptionalcourseScore() {
            double score = totalScore.get();
            if (score >= 90) {
                return 10;
            }
            if (score >= 80) {
                return 20;
            }
            if (score >= 70) {
                return 30;
            }
            if (score >= 60) {
                return 40;
            }
            return 60;
        }
    }
    View Code

    方法三:变量+final,即变成常量(只能读,不能修改)

    class StudentAssistant {
    
        final double passScore = 60;
    }

    二、从锁着手【公共区域(堆内存)的数据,要被多个线程操作时,为了确保数据的安全(或一致)性,需要在数据旁边放一把锁,要想操作数据,得先获取锁】

    方法一:悲观锁【认定数据一定不安全,不管怎样,想访问数据就需要锁,没锁的访问不了】

    class ClassAssistant {
    
        double totalScore = 60;
        final Lock lock = new Lock();
    
        void addScore(double score) {
            lock.obtain();    //获取锁
            totalScore += score;
            lock.release();   //释放锁
        }
    
        void subScore(double score) {
            lock.obtain();
            totalScore -= score;
            lock.release();
        }
    }

    方法二:乐观锁【在高并发时可以用悲观锁,但在低并发时,数据被意外修改的概率很低,(假如只有一个线程)再用悲观锁(获得锁、释放锁)可能就会造成浪费,这时可以用乐观锁即CAS】

    乐观锁:假如一个线程操作数据,做到一半,休息了,就记录下数据的值,等回来继续做时,先将记录的数据与当前数据对比,如果一样就继续干,不一样就重新做。

    乐观锁存在ABA问题,即数据有可能被变动过了,但后面又改了回来,这时数据值没变,但其实被动过了。

    解决ABA问题:加一个版本号字段,数据若变动一次,版本号就加一,变动两次就加二。

     

      

  • 相关阅读:
    Nginx访问日志、 Nginx日志切割、静态文件不记录日志和过期时间
    nginx的安装 、Nginx默认虚拟主机、nginx用户认证、nginx 域名重定向
    lnmp架构、mysql的安装、php的安装、nginx相关
    限定某个目录禁止解析php 、限制user_agent 、php的配制文件、PHP的动态扩展模块
    配置url防盗链、目录权限访问控制Directory、文件访问权限控制FilesMatch
    指令的概述
    点击事件交互示例
    日期过滤器示例
    in和not in注意事项
    mysql里的case用法详解
  • 原文地址:https://www.cnblogs.com/yuanmaolin/p/11090380.html
Copyright © 2011-2022 走看看