知识大全 为什么要进行数据同步

Posted 变量

篇首语:人的大脑和肢体一样,多用则灵,不用则废。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 为什么要进行数据同步相关的知识,希望对你有一定的参考价值。

Java多线程初学者指南(9):为什么要进行数据同步  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  Java中的变量分为两类 局部变量和类变量 局部变量是指在方法内定义的变量 如在run方法中定义的变量 对于这些变量来说 并不存在线程之间共享的问题 因此 它们不需要进行数据同步 类变量是在类中定义的变量 作用域是整个类 这类变量可以被多个线程共享 因此 我们需要对这类变量进行数据同步

  数据同步就是指在同一时间 只能由一个线程来访问被同步的类变量 当前线程访问完这些变量后 其他线程才能继续访问 这里说的访问是指有写操作的访问 如果所有访问类变量的线程都是读操作 一般是不需要数据同步的

  那么如果不对共享的类变量进行数据同步 会发生什么情况呢?让我们先看看下面的代码会发生什么样的事情

   package test;public class MyThread extends Thread    public static int n =  ;    public void run()            int m = n;        yield();        m++;        n = m;        public static void main(String[] args) throws Exception            MyThread myThread = new MyThread ();        Thread threads[] = new Thread[ ];        for (int i =  ; i < threads length; i++)            threads[i] = new Thread(myThread);        for (int i =  ; i < threads length; i++)            threads[i] start();        for (int i =  ; i < threads length; i++)            threads[i] join();        System out println( n =   + MyThread n);    

  在执行上面代码的可能结果如下

   n = 

  看到这个结果 可能很多读者会感到奇怪 这个程序明明是启动了 个线程 然后每个线程将静态变量n加 最后使用join方法使这 个线程都运行完后 再输出这个n值 按正常来讲 结果应该是n = 可偏偏结果小于

  其实产生这种结果的罪魁祸首就是我们经常提到的 脏数据 而run方法中的yield()语句就是产生 脏数据 的始作俑者(不加yield语句也可能会产生 脏数据 但不会这么明显 只有将 改成更大的数 才会经常产生 脏数据 在本例中调用yield就是为了放大 脏数据 的效果) yield方法的作用是使线程暂停 也就是使调用yield方法的线程暂时放弃CPU资源 使CPU有机会来执行其他的线程 为了说明这个程序如何产生 脏数据 我们假设只创建了两个线程 thread 和thread 由于先调用了thread 的start方法 因此 thread 的run方法一般会先运行 当thread 的run方法运行到第一行(int m = n )时 将n的值赋给m 当执行到第二行的yield方法后 thread 就会暂时停止执行 而当thread 暂停时 thread 获得了CPU资源后开始运行(之前thread 一直处于就绪状态) 当thread 执行到第一行(int m = n )时 由于thread 在执行到yield时n仍然是 因此 thread 中的m获得的值也是 这样就造成了thread 和thread 的m获得的都是 在它们执行完yield方法后 都是从 开始加 因此 无论谁先执行完 最后n的值都是 只是这个n被thread 和thread 各赋了一遍值 这个过程如下图如示

  

  也许有人会问 如果只有n++ 会产生 脏数据 吗?答案是肯定的 那么n++只是一条语句 又如何在执行过程中将CPU交给其他的线程呢?其实这只是表面现象 n++在被Java编译器编译成中间语言(也叫做字节码)后 并不是一条语言 让我们看看下面的Java代码将会被编译成什么样的Java中间语言

  Java源代码

   public void run()    n++;

  被编译后的中间语言代码

        public void run()              aload_                   dup                      getfield         iconst_                  iadd                     putfield                return               

  大家可以看到在run方法中只有n++一条语句 而在编译后 却有 条中间语言语句 我们并不需要知道这些语句的功能是什么 只看一下第 和 行语句 在 行是getfield 根据它的英文含义可知是要得到某个值 因为这里只有一个n 所以毫无疑问 是要得到n的值 而在 行的iadd也不难猜测是将这个得到的n值加 在 行的putfield的含义我想大家可能已经猜出来了 它负责将这个加 后的n再更新回类变量n 说到这 可能大家还有一个疑惑 执行n++时直接将n加 不就行了 为什么要如此费周折 其实这里涉及到一个Java内存模型的问题

  Java的内存模型分为主存储区和工作存储区 主存储区保存了Java中所有的实例 也就是说 在我们使用new来建立一个对象后 这个对象及它内部的方法 变量等都保存在这一区域 在MyThread类中的n就保存在这个区域 主存储区可以被所有线程共享 而工作存储区就是我们前面所讲的线程栈 在这个区域里保存了在run方法以及run方法所调用的方法中定义的变量 也就是方法变量 在线程要修改主存储区中的变量时 并不是直接修改这些变量 而是将它们先复制到当前线程的工作存储区 在修改完后 再将这个变量值覆蓋主存储区的相应的变量值

cha138/Article/program/Java/gj/201311/27623

相关参考

知识大全 微软同步框架中的自定义数据同步基础

  MicrosoftSyncFramework(MSF)为我们提供了进行同步应用开发的基础框架和API这些API即有基于托管代码的也有基于非托管代码的也就是说我们既可以开发基于NET平台使用托管AP

知识大全 同步两个SQLServer数据库

同步两个SQLServer数据库  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  如何同步两个SQ

知识大全 解决不同字符集数据库间的数据同步问题

  解决不同字符集数据库间的数据同步问题  首先在原数据库上做一个视图对保存汉字的字段加包函数utl_raw_cast_to_raw(保存汉字的字段)  在新数据库上做个数据库连接连接指向原数据库之后

知识大全 如何通过触发器实现数据库的即时同步

问题如何通过触发器实现数据库的即时同步?  解答具体的解决方法请参考下文  即时同步两个表的示例如下:    测试环境如下:SQLSever数据库远程主机名:xz用户名:sa密码:无数据库名:test

知识大全 关于OracleRac数据不同步

关于OracleRac数据不同步  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  现在有这样的环境

知识大全 Java多线程共享数据、同步、通信

Java多线程共享数据、同步、通信  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一线程共享数据

知识大全 SQL Server数据库同步问题

SQLServer数据库同步问题  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  我们可以通过数据

知识大全 使ACCESS数据库保持同步

使ACCESS数据库保持同步  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 MYSQL的master/slave数据同步配置

MYSQL的master/slave数据同步配置  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 两台SQL Server数据同步解决方案

两台SQLServer数据同步解决方案  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  复制的概念