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

来源:互联网 发布:js 判断event 编辑:程序博客网 时间:2024/06/05 19:29
    首先,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();        }//每次运行的结果都有可能不同,可能1000        System.out.println("结果是:"+Main.count);    }}

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

原创粉丝点击