java数据同步用什么区别 java中同步和异步有什么异同
大家好,如果您还对java数据同步用什么区别不太了解,没有关系,今天就由本站为大家分享java数据同步用什么区别的知识,包括java中同步和异步有什么异同的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!
java中同步和异步有什么异同
Java中交互方式分为同步和异步两种:
相同的地方:
都属于交互方式,都是发送请求。
不同的地方:
同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;
异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。
Java,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称。用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算。从此,Java被广泛接受并推动了Web的迅速发展,常用的浏览器现均支持Java applet
Java是一种简单的,面向对象的,分布式的,解释型的,健壮安全的,结构中立的,可移植的,性能优异、多线程的动态语言。
当1995年SUN推出Java语言之后,全世界的目光都被这个神奇的语言所吸引。那么Java到底有何神奇之处呢?
Java语言其实最早诞生于1991年,起初被称为OAK语言,是SUN公司为一些消费性电子产品而设计的一个通用环境。他们最初的目的只是为了开发一种独立于平台的软件技术,而且在网络出现之前,OAK可以说是默默无闻,甚至差点夭折。但是,网络的出现改变了OAK的命运。
参考资料:java基础百度百科Java多线程初学者指南(9):为什么要进行数据同步
Java中的变量分为两类局部变量和类变量局部变量是指在方法内定义的变量如在run方法中定义的变量对于这些变量来说并不存在线程之间共享的问题因此它们不需要进行数据同步类变量是在类中定义的变量作用域是整个类这类变量可以被多个线程共享因此我们需要对这类变量进行数据同步
数据同步就是指在同一时间只能由一个线程来访问被同步的类变量当前线程访问完这些变量后其他线程才能继续访问这里说的访问是指有写操作的访问如果所有访问类变量的线程都是读操作一般是不需要数据同步的
那么如果不对共享的类变量进行数据同步会发生什么情况呢?让我们先看看下面的代码会发生什么样的事情
packagetest;publicclassMyThreadextendsThread{publicstaticintn=;publicvoidrun(){intm=n;yield();m++;n=m;}publicstaticvoidmain(String[]args)throwsException{MyThreadmyThread=newMyThread();Threadthreads[]=newThread[ ];for(inti=;i<threads length;i++)threads[i]=newThread(myThread);for(inti=;i<threads length;i++)threads[i] start();for(inti=;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源代码
publicvoidrun(){n++;}
被编译后的中间语言代码
publicvoidrun(){ 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方法所调用的方法中定义的变量也就是方法变量在线程要修改主存储区中的变量时并不是直接修改这些变量而是将它们先复制到当前线程的工作存储区在修改完后再将这个变量值覆盖主存储区的相应的变量值
lishixinzhi/Article/program/Java/gj/201311/27623java同步方法和同步代码块的区别
在Java语言中,每一个对象有一把锁。线程可以使用synchronized关键字来获取对象上的锁。synchronized关键字可应用在方法级别(粗粒度锁)或者是代码块级别(细粒度锁)。
问题的由来:
看到这样一个面试题:
//下列两个方法有什么区别public synchronized void method1(){} public void method2(){ synchronized(obj){}}
synchronized用于解决同步问题,当有多条线程同时访问共享数据时,如果进行同步,就会发生错误,Java提供的解决方案是:只要将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他线程不能进来执行可以。解决这个问题。这里在用synchronized时会有两种方式,一种是上面的同步方法,即用synchronized来修饰方法,另一种是提供的同步代码块。
这里总感觉怪怪的,这两种方法有什么区别呢,基础学得不好,于是就动手做了个简单的测试,代码如下:
public class SynObj{ public synchronized void methodA(){ System.out.println("methodA....."); try{ Thread.sleep(5000);} catch(InterruptedException e){ e.printStackTrace();}} public void methodB(){ synchronized(this){ System.out.pritntln("methodB.....");}} public void methodC(){ String str="sss"; synchronized(str){ System.out.println("methodC.....");}}}
public class TestSyn{ public static void main(String[] args){ final SynObj obj= new SynObj(); Thread t1= new Thread(new Runnable(){@Override public void run(){ obj.methodA();}}); t1.start(); Thread t2= new Thread(new Runnable(){@Override public void run(){ obj.methodB();}}); t2.start(); Thread t3= new Thread(new Runnable(){@Override public void run(){ obj.methodC();}}); t3.start();}}
这段小代码片段打印结果如下:
methodA.....methodC.....//methodB会隔一段时间才会打印出来methodB.....
这段代码的打印结果是,methodA…..methodC…..会很快打印出来,methodB…..会隔一段时间才打印出来,那么methodB为什么不能像methodC那样很快被调用呢?
在启动线程1调用方法A后,接着会让线程1休眠5秒钟,这时会调用方法C,注意到方法C这里用synchronized进行加锁,这里锁的对象是str这个字符串对象。但是方法B则不同,是用当前对象this进行加锁,注意到方法A直接在方法上加synchronized,这个加锁的对象是什么呢?显然,这两个方法用的是一把锁。
*由这样的结果,我们就知道这样同步方法是用什么加锁的了,由于线程1在休眠,这时锁还没释放,导致线程2只有在5秒之后才能调用方法B,由此,可知两种加锁机制用的是同一个锁对象,即当前对象。
另外,同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好*。
OK,本文到此结束,希望对大家有所帮助。