多线程访问共享数据同步原因

    首先,JVM中堆空间(存放对象)、方法区(存放静态变量、常量)、常量池(String常量池、整形常量池)是线程共享的空间,Java栈空间是线程私有的,每个线程都有一个栈空间,执行一个方法时会创建一个栈帧,压入栈中,栈帧中保存局部变量、方法参数、中间变量的值,方法返回后栈帧弹出。线程读取堆、方法区、常量池中数据后,存放在线程栈中,对栈中的值操作完成后,再写回堆、方法区、常量池中,如果多个线程同时改动共享数据的话,可能会出现一个线程操作后的结果被其他线程返回的结果覆盖掉(同时写)或者一个线程读取到的数据是其他线程改动后的结果(一个线程读、一个线程写)。所以要对共享数据(共享内存中的数据)进行同步,一个时刻只能有一个线程进行写操作,该线程执行完成后,其他线程才能访问。

    例如下面的例子,1000个线程同时对共享变量count进行加1,所有线程执行结束后,count值理应是1000,然而结果并非总是1000.

public class Main {
    public static int count = 0;

    public static void countNum() {
        //休眠一毫秒,结果更明显
        try {
            Thread.sleep(1);

        } catch (Exception e) {

        }
        count++;
    }

    public static void main(String[] args) {
        //同时启动1000个线程,每个线程加1,观察实际结果是否是1000
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                public void run() {
                    Main.countNum();
                }
            }).start();
        }
        //主线程休眠2秒钟,保证1000个线程已经执行完成
        try {
            Thread.sleep(2000);
        } catch (Exception e) {

        }

        //每次运行的结果都有可能不同,可能1000
        System.out.println("结果是:" + Main.count);
    }
}


    如果线程1从方法区(线程共享空间)复制变量到当前线程栈内存后,修改完成,还没写回方法区前,此时其他线程执行了写操作并写回了方法区,然后线程1将结果写回方法区,会导致其他线程的操作结果被线程1覆盖。

 

 

 

你可能感兴趣的:(Java)