JMM之Happens-Before规则

介绍:
        大家好,我是照着赶紧抄。
   
目录:    
        今天跟大家分享一下Java内存模型(JMM)之初识Happens-Before规则。
   

前言:    
        相信从事开发的同行们都知道,导致并发问题主要是可见性和有序性这两个问题。影响可见行性的原因是缓存,影响有序性的问题是编译器优化。如何去解决这两个问题呢,大家会说上锁,不管轻量级锁还是重量级锁,上就完了。volatile和synchronized和final三个关键字就会时常出现在大家的代码里(只管实现需求,不管服务器性能,who care?)。嘿嘿,放松一下心情,言归正传。下面我们就说一下什么是Happens-Before规则。
   

正题:什么是Happens-Before?
        在JMM中,在一个线程中,或不同的线程中。如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在Happens-Before关系。值得一提的是,我们说两个操作存在Happens-Before关系。这里指的操作的结果。并非执行顺序。 

    Happens-Before与我们密切相关的规则:

        1.程序顺序规则:一个线程中的每个操作,Happens-Before于该线程中的任意后续操作;

        例子:

 public class HappensBefore {

            static int a = 8;
            static boolean flag = true;

            public static void outPrint() {

                if (flag) {
                    System.out.println(a);
                }
            }

            public static void main(String args[]) {
                HappensBefore.outPrint();
            }
        }

    总结:这里我觉得可以通俗的总结下,就是程序是从上而下执行的。

        2.监视器锁规则:对一个锁的解锁,Happens-Before于随后对这个锁的加锁;

        例子:

  public class HappensBefore {

            long num = 0;

            public synchronized void Increment() {
                num++;
            }

            public synchronized void get() {
                System.out.println(num);
            }
        }

    总结:无论在单核CPU还是多核CPU的时候,指的是前一个线程的解锁操作对后一个线程的加锁操作可见。这个也叫做管程。

        3.volatile变量规则:被volatile修改的变量写操作,Happens-Before于任意后续对这个变量操作的读;

        例子:

   public class HappensBefore {

            static volatile long num = 0;


            static Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                     num ++;
                }
            });

             static Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(num);
                }
            });

            public static void main(String args[]) {
                HappensBefore.thread1.start();
                HappensBefore.thread2.start();
            }
        }

    总结:当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存上。
               当读一个volatile变量时,JMM会把该线程对应的本地缓存置为无效,从主内存中重新读取变量。

        4.传递性:A Happens-Before B ,B Happens-Before C,那么 A Happens-Before C

        如下图:

JMM之Happens-Before规则_第1张图片

        例子:

public class HappensBefore {

            static int x = 0;
            static volatile boolean flag = false;
    
         static Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                x = 42; //1⃣️
                flag = true;// 2⃣️
                }
            });

        static Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                if (flag) {3⃣️
                    System.out.println(x);
                    }
                }
            });
        }

        总结:1⃣️ Happens-Before 2⃣️ , 2⃣️ Happens-Before 3⃣️ , 1⃣️ Happens-Before 3⃣️ 。
                   所以当线程2读取到flag为真的时候,就自然而然的知道了,x的值是42了。

    给大家出一个问题,希望大家积极回答!     

public class Singleton {

    private static Singleton singleton;

    public Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

       这段代码少了什么?应该加上什么就完美了?然后说明一下为什么要加这个?

你可能感兴趣的:(技术)