美文网首页
二、线程安全性

二、线程安全性

作者: RainySpring | 来源:发表于2020-04-17 00:30 被阅读0次

    要编写线程安全的代码其核心在于要对状态访问操作进行管理,特别是对共享的(shared)和可变的(Mutable)状态的访问。
    -- 《Java并发编程实战》

    知识储备:非状态、竞争条件、原子操作

    1、多线程访问同一个可变的状态变量,怎么解决?

    • 不在线程之前共享该状态变量
    • 将这个可变的状态变量改为不变的
    • 在访问状态变量使用同步

    2、什么是线程安全性?
    当多个线程访问某个类时,这个类始终表现出正确的行为。这个类就是线程安全的。

    3、什么是无状态?
    无状态对象一定是线程安全的,就是没有包含任何域,也不包括任何对其他类中域的引用。大多数Servlet都是无状态的。


    image.png

    非原子性操作会造成 竞态条件:读取-修改-写入
    还有一种 延迟初始化(单例模式)的竞态条件:先检查后执行
    这些计算的正确性取决于多个线程的交替执行时序,就会发生竞态条件。

    private SingleObject  single = null;
    public getInstance(){
      if  (single == null){
          single = new SingleObject();
      }
    }
    

    4、竞态条件在并发情况永远是错误的吗?
    并不是总是产生错误,还是需要某种不恰当的执行时序。

    5、复合操作和原子操作
    假设有2个操作A和B,对于执行A的线程来说,另一个执行B的线程要么全部执行完,要么完全不执行,那么A和B对彼此来说就是原子操作,反之是复合操作。
    eg. int i = 0;i++ 就是一种读取-修改-写入的复合操作
    eg.AtomicLong i = new AtomicLong (0); i.incrementAndGet();就是原子操作
    AtomicLong 是线程安全的对象,在实际情况中我们尽量使用这种线程安全的对象来管理类的状态。

    加锁机制

    1、原子操作无法解决的问题

    如果一个类中有更多的状态变量时,是否只需要加入线程安全状态变量就足够了?
    不是,依然存在竞态条件

    //2个原子状态量
    public AtomicInteger a = new AtomicInteger(0);
    public AtomicInteger b = new AtomicInteger(0);
        public void service(){
            if(...){
                a.get(); //1
            }else{
                a.incrementAndGet();//2
                b.incrementAndGet();
            }
        }
    

    虽然状态变量都是原子操作,假设线程小红刚跑到1位置,正要获取a的值,此时线程小明跑到2位置并将a的值累加了,那么小红获取的值就是个不正确状态的值!

    2、内置锁(互斥锁) - 同步代码块(Synchronized)

    synchronized(lock){
      //访问或修改 由锁保护的共享状态
    }
    

    lock:以class为锁;代码块组成一组不可分割的原子单元。

    3、锁重入

    某个线程请求一个由其他线程持有的锁时,当前线程会被阻塞;
    但是试图获取一个由自己持有的锁,这个请求就会成功,否则造成死锁。
    “重入”意味着锁的操作粒度是“线程”,而不是“调用”。

    4、一种加锁的约定

    将所有的可变状态都封装在对象内部,通过对象的内置锁对其进行同步,就不会出现并发访问了。

    5、活跃性和性能

    synchronized会造成一种串行阻塞性的不良并发,性能低;
    怎么缓解?
    掌握在简单性(最简单的就是对整个方法进行同步)与并发性(对尽可能短的代码块进行同步)之间的平衡,既不能太简单省事,也不能加太多的同步代码块,分的太短太细。

    //这种同步代码短,但是在for循环中锁次数较多 影响性能
    for(){
      synchronized(this){
      }
    }
    //这样加比较好,所以要在这两者间平衡
    synchronized(this){
      for(){}
    }
    
    

    学习中,有不足之处欢迎指出!感谢

    相关文章

      网友评论

          本文标题:二、线程安全性

          本文链接:https://www.haomeiwen.com/subject/ehufvhtx.html