您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 人事档案/员工关系 > synchronized的作用
synchronized的作用一、同步方法publicsynchronizedvoidmethodAAA(){//….}锁定的是调用这个同步方法的对象测试:a、不使用这个关键字修饰方法,两个线程调用同一个对象的这个方法。目标类:1publicclassTestThread{2publicvoidexecute(){//synchronized,未修饰3for(inti=0;i100;i++){4System.out.println(i);5}6}7}线程类:1publicclassThreadAimplementsRunnable{2TestThreadtest=null;3publicThreadA(TestThreadpTest){//对象有外部引入,这样保证是同一个对象4test=pTest;5}6publicvoidrun(){7test.execute();8}9}调用:1TestThreadtest=newTestThread();2Runnablerunabble=newThreadA(test);3Threada=newThread(runabble,A);4a.start();5Threadb=newThread(runabble,B);6b.start();结果:输出的数字交错在一起。说明不是同步的,两个方法在不同的线程中是异步调用的。b、修改目标类,增加synchronized修饰1publicclassTestThread{2publicsynchronizedvoidexecute(){//synchronized修饰3for(inti=0;i100;i++){4System.out.println(i);5}6}7}结果:输出的数字是有序的,首先输出A的数字,然后是B,说明是同步的,虽然是不同的线程,但两个方法是同步调用的。注意:上面虽然是两个不同的线程,但是是同一个实例对象。下面使用不同的实例对象进行测试。c、每个线程都有独立的TestThread对象。目标类:1publicclassTestThread{2publicsynchronizedvoidexecute(){//synchronized修饰3for(inti=0;i100;i++){4System.out.println(i);5}6}7}线程类:1publicclassThreadAimplementsRunnable{2publicvoidrun(){3TestThreadtest=newTestThread();4test.execute();5}6}7调用:1Runnablerunabble=newThreadA();2Threada=newThread(runabble,A);3a.start();4Threadb=newThread(runabble,B);5b.start();结果:输出的数字交错在一起。说明虽然增加了synchronized关键字来修饰方法,但是不同的线程调用各自的对象实例,两个方法仍然是异步的。引申:对于这种多个实例,要想实现同步即输出的数字是有序并且按线程先后顺序输出,我们可以增加一个静态变量,对它进行加锁(后面将说明锁定的对象)。修改目标类:1publicclassTestThread{2privatestaticObjectlock=newObject();//必须是静态的。3publicvoidexecute(){4synchronized(lock){5for(inti=0;i100;i++){6System.out.println(i);7}8}9}10}二、同步代码块1publicvoidmethod(SomeObjectso){2synchronized(so)3//…..4}5}锁定一个对象,其实锁定的是该对象的引用(objectreference)谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以按上面的代码写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它必须是一个对象)来充当锁(上面的解决方法就是增加了一个状态锁)。a、锁定一个对象,它不是静态的privatebyte[]lock=newbyte[0];//特殊的instance变量目标类:1publicclassTestThread{2privateObjectlock=newObject();3publicvoidexecute(){4synchronized(lock){//增加了个锁,锁定了对象lock,在同一个类实例中,是线程安全的,但不同的实例还是不安全的。56因为不同的实例有不同对象锁lock7for(inti=0;i100;i++){8System.out.println(i);9}10}11}12}其实上面锁定一个方法,等同于下面的:1publicvoidexecute(){2synchronized(this){//同步的是当然对象3for(inti=0;i100;i++){4System.out.println(i);5}6}7}b、锁定一个对象或方法,它是静态的这样锁定,它锁定的是对象所属的类publicsynchronizedstaticvoidexecute(){//...}等同于1publicclassTestThread{2publicstaticvoidexecute(){3synchronized(TestThread.class){4//5}6}7}测试:目标类:1publicclassTestThread{2privatestaticObjectlock=newObject();3publicsynchronizedstaticvoidexecute(){//同步静态方法4for(inti=0;i100;i++){5System.out.println(i);6}7}8publicstaticvoidexecute1(){9for(inti=0;i100;i++){10System.out.println(i);11}12}13publicvoidtest(){14execute();//输出是有序的,说明是同步的15//execute1();//输出是无须的,说明是异步的16}17}线程类:调用不同的方法,于是建立了两个线程类1publicclassThreadAimplementsRunnable{2publicvoidrun(){3TestThread.execute();//调用同步静态方法4}5}6publicclassThreadBimplementsRunnable{7publicvoidrun(){8TestThreadtest=newTestThread();9test.test();//调用非同步非静态方法10}11}调用:1RunnablerunabbleA=newThreadA();2Threada=newThread(runabbleA,A);3a.start();4RunnablerunabbleB=newThreadB();5Threadb=newThread(runabbleB,B);6b.start();注意:1、用synchronized来锁定一个对象的时候,如果这个对象在锁定代码段中被修改了,则这个锁也就消失了。看下面的实例:目标类:1publicclassTestThread{2privatestaticfinalclassTestThreadHolder{3privatestaticTestThreadtheSingleton=newTestThread();4publicstaticTestThreadgetSingleton(){5returntheSingleton;6}7privateTestThreadHolder(){8}9}1011privateVectorve=null;12privateObjectlock=newObject();13privateTestThread(){14ve=newVector();15initialize();16}17publicstaticTestThreadgetInstance(){18returnTestThreadHolder.getSingleton();19}20privatevoidinitialize(){21for(inti=0;i100;i++){22ve.add(String.valueOf(i));23}24}25publicvoidreload(){26synchronized(lock){27ve=null;28ve=newVector();29//lock=abc;30for(inti=0;i100;i++){31ve.add(String.valueOf(i));32}33}34System.out.println(reloadend);35}3637publicbooleancheckValid(Stringstr){38synchronized(lock){39System.out.println(ve.size());40returnve.contains(str);41}42}43}说明:在reload和checkValid方法中都增加了synchronized关键字,对lock对象进行加锁。在不同线程中对同一个对象实例分别调用reload和checkValid方法。在reload方法中,不修改lock对象即注释lock=abc;,结果在控制台输出reloadend后才输出100。说明是同步调用的。如果在reload方法中修改lock对象即去掉注释,结果首先输出了一个数字(当前ve的大小),然后输出reloadend。说明是异步调用的。2、单例模式中对多线程的考虑1publicclassTestThread{2privatestaticfinalclassTestThreadHolder{3privatestaticTestThreadtheSingleton=newTestThread();4publicstaticTestThreadgetSingleton(){5returntheSingleton;6}7privateTestThreadHolder(){8}9}10privateVectorve=null;11privateObjectlock=newObject();12privateTestThread(){13ve=newVector();14initialize();15}16publicstaticTestThreadgetInstance(){17returnTestThreadHolder.getSingleton();18}19'''20}说明:增加了一个内部类,在内部类中申明一个静态的对象,实例化该单例类,初始化的数据都在单例类的构造函数中进行。这样保证了多个实例同时访问的时候,初始化的数据都已经成功初始化了。总结:A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁,所以首先应知道需要加锁的对象B.每个对象只有一个锁(lock)与之相关联。C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
本文标题:synchronized的作用
链接地址:https://www.777doc.com/doc-997133 .html