多线程开发

1.可见性

可见性:一个线程对共享变量值的修改,能够及时地被其他线程看到。
共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是几个线程的共享变量。

2.Java内存模型(JMM)

Java内存模型(Java Memory Model)描述了java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。

  • 所有的变量都存储在主内存中
  • 每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)

两条规定:

  • 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从内存中读写;
  • 不同线程之间无法直接访问其他工作内存中的变量,线程间变量值的传递需要通过主内存来完成;
多线程开发_第1张图片
Java内存模型.png

3.valite(保证可见性,不保证复合操作的原子性,例如++,--)

  • volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫线程将最近的值刷新到主内存。
  • 通过加入内存屏障和禁止重排序优化来实现的。
  • 对变量的写入操作不依赖其当前值

4. synchronized(保证可见性,保证原子性)

Java中的每一个对象都可以作为锁,悲观锁

  • 对于普通同步方法,锁是当前实例对象(对象被线程A访问其中一个方法,线程B不能访问对象的任意一个方法)

  • 对于静态同步方法,锁是当前类的Class对象(对象被线程A访问静态同步方法,线程B不能访问Class的所有对象)

  • 对于同步方法块,锁是synchronized括号配置的对象

测试程序

public class Main {

    public static void main(String []arg){

        TestClass testInstance1 = new TestClass();

        TestClass testInstance2 = new TestClass();

        //=========================静态同步方法============================
        //静态同步方法A
        new Thread(new Runnable() {
            @Override
            public void run() {
                TestClass.methodStaticSyncA("静态同步方法A");
            }
        }).start();

        //静态同步方法B
        new Thread(new Runnable() {
            @Override
            public void run() {
                TestClass.methodStaticSyncB("静态同步方法B");
            }
        }).start();

        //=========================实例1普通方法============================
        //实例1--普通方法A
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance1.methodNormalA("实例1--普通方法A");
            }
        }).start();

        //实例1--普通方法B
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance1.methodNormalB("实例1--普通方法B");
            }
        }).start();

        //=========================实例2普通方法============================

        //实例2--普通方法A
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance1.methodNormalA("实例2--普通方法A");
            }
        }).start();

        //实例2--普通方法B
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance1.methodNormalB("实例2--普通方法B");
            }
        }).start();

        //=========================实例1同步方法============================

        //实例1--同步方法A
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance1.methodSyncA("实例1--同步方法A");
            }
        }).start();


        //实例1--同步方法B
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance1.methodSyncB("实例1--同步方法B");
            }
        }).start();

        //=========================实例2同步方法============================
        //实例2--同步方法A
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance2.methodSyncA("实例2--同步方法A");
            }
        }).start();


        //实例2--同步方法B
        new Thread(new Runnable() {
            @Override
            public void run() {
                testInstance2.methodSyncB("实例2--同步方法B");
            }
        }).start();




    }
}

 class TestClass {


    public void methodNormalA(String tag){


        System.out.println(tag+" methodNormalA: ");
        while(true);

    }

     public void methodNormalB(String tag){


         System.out.println(tag+" methodNormalB: ");
         while(true);

     }

    public synchronized void methodSyncA(String tag){


        System.out.println(tag+" methodSyncA: ");
        while(true);

    }

     public synchronized void methodSyncB(String tag){


         System.out.println(tag+" methodSyncB: ");
         while(true);

     }

    public synchronized static void methodStaticSyncA(String tag){


        System.out.println(tag+" methodStaticSyncA: ");
        while(true);

    }

     public synchronized static void methodStaticSyncB(String tag){


         System.out.println(tag+" methodStaticSyncB: ");
         while(true);

     }
}



测试结果
静态同步方法A methodStaticSyncA: 
实例1--普通方法A methodNormalA: 
实例1--普通方法B methodNormalB: 
实例2--普通方法A methodNormalA: 
实例2--普通方法B methodNormalB: 
实例1--同步方法A methodSyncA: 
实例2--同步方法A methodSyncA: 

结论

  • 普通方法,同步方法,静态同步方法相互独立,互不影响
  • 普通方法不受锁的影响
  • 在同一实例对象内同步方法之间互斥,不同实例互不影响;
  • 静态同步方法之间互斥

5.synchronized VS volatile

  • volatile 不需要枷锁,比synchronized更轻量级,不会阻塞线程。
  • 从内存可见性角度,volatile读相当于枷锁,volatile写相当于解锁;
  • synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性

参考

共享变量在线程间的可见性

你可能感兴趣的:(多线程开发)