zoukankan      html  css  js  c++  java
  • 线程安全性

    一、线程安全在三个方面体现

    1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);

    2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);

    3.有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。

    二、原子性---atomic

    JDK里面提供了很多atomic类,AtomicInteger,AtomicLong,AtomicBoolean等等。

     

     

     

    三、原子性---synchronized

    synchronized是一种同步锁,通过锁实现原子操作。

    JDK提供锁分两种:一种是synchronized,依赖JVM实现锁,因此在这个关键字作用对象的作用范围内是同一时刻只能有一个线程进行操作;另一种是LOCK,是JDK提供的代码层面的锁,依赖CPU指令,代表性的是ReentrantLock。

    synchronized修饰的对象有四种:

    • 修饰代码块,作用于调用的对象;
    • 修饰方法,作用于调用的对象;
    • 修饰静态方法,作用于所有对象;
    • 修饰类,作用于所有对象。

    四、可见性---volatile

    对于可见性,JVM提供了synchronized和volatile。

    (1)volatile的可见性是通过内存屏障和禁止重排序实现的

    volatile会在写操作时,会在写操作后加一条store屏障指令,将本地内存中的共享变量值刷新到主内存:

    (1)volatile的可见性是通过内存屏障和禁止重排序实现的

    volatile会在写操作时,会在写操作后加一条store屏障指令,将本地内存中的共享变量值刷新到主内存:

    五、有序性

    有序性是指,在JMM中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

    可以通过volatile、synchronized、lock保证有序性。

    另外,JMM具有先天的有序性,即不需要通过任何手段就可以得到保证的有序性。这称为happens-before原则。

    如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性。虚拟机可以随意地对它们进行重排序。

    happens-before原则:

    1. 程序次序规则:在一个单独的线程中,按照程序代码书写的顺序执行。
    2. 锁定规则:一个unlock操作happen—before后面对同一个锁的lock操作。
    3. volatile变量规则:对一个volatile变量的写操作happen—before后面对该变量的读操作。
    4. 线程启动规则:Thread对象的start()方法happen—before此线程的每一个动作。
    5. 线程终止规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
    6. 线程中断规则:对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。
    7. 对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。
    8. 传递性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。

    =============================>

    static  静态修饰关键字,可以修饰 变量,程序块,类的方法;

     当你定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存;

      修饰一个程序块的时候(也就是直接将代码写在static{...}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化;
      当修饰一个类方法时候你就可以直接通过类来调用而不需要新建对象。

    final 只能赋值一次;修饰变量、方法及类,
      当你定义一个final变量时,jvm会将其分配到常量池中,程序不可改变其值;当你定义一个方法时,该方法在子类中将不能被重写;当你修饰一个类时,该类不能被继承。
    volatile
    volatile也是变量修饰符,只能用来修饰变量。volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
    volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
  • 相关阅读:
    关于二叉树遍历的一点想法
    Mysqldump导入数据库很慢的解决办法
    javascript笔记收集
    再次讨论二叉树--如何根据先序和中序推选后序
    一道图的题目-拓扑序概念
    一道哈夫曼二叉树题目--稍微容易一点
    一道哈夫曼树的题目--好不容易
    证明二叉树节点数公式
    一道二叉树题目---顺序存储二叉树位置同层的关系
    POJ 3253 Fence Repair(贪心)
  • 原文地址:https://www.cnblogs.com/KL2016/p/15119524.html
Copyright © 2011-2022 走看看