`

[zz] Synchronized和Static Synchronized区别

 
阅读更多

 通过分析这两个用法的分析,我们可以理解java中锁的概念。一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念),一个是全局锁(该锁针对的是类,无论实例多少个对象,那么线程都共享该锁)。实例锁对应的就是synchronized关键字,而类锁(全局锁)对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。下面的文章做了很好的总结:

 

1.synchronized与static synchronized 的区别
       synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问改实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于 this.synchronized,而static synchronized相当于Something.synchronized.


         一个日本作者-结成浩的《java多线程设计模式》有这样的一个列子:

  1. pulbic class Something(){  
  2.     public synchronized void isSyncA(){}  
  3.     public synchronized void isSyncB(){}  
  4.     public static synchronized void cSyncA(){}  
  5.     public static synchronized void cSyncB(){}  
  6. }  


       那么,加入有Something类的两个实例a与b,那么下列组方法何以被1个以上线程同时访问呢

  1. a. x.isSyncA()与x.isSyncB()   
  2. b. x.isSyncA()与y.isSyncA()  
  3. c. x.cSyncA()与y.cSyncB()  
  4. d. x.isSyncA()与Something.cSyncA()  


      这里,很清楚的可以判断:
a,都是对同一个实例的synchronized域访问,因此不能被同时访问
b,是针对不同实例的,因此可以同时被访问
c,因为是static synchronized,所以不同实例之间仍然会被限制,相当于Something.isSyncA()与 Something.isSyncB()了,因此不能被同时访问。
那么,第d呢?,书上的 答案是可以被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同的原因。
个人分析也就是synchronized 与static synchronized 相当于两帮派,各自管各自,相互之间就无约束了,可以被同时访问。目前还不是分清楚java内部设计synchronzied是怎么样实现的。


结论:A: synchronized static是某个类的范围,synchronized static cSync{}防止多个线程同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。

B: synchronized 是某实例的范围,synchronized isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。



2.synchronized方法与synchronized代码快的区别
        synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是
synchronized methods(){} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。


3.synchronized关键字是不能继承的
        这个在
http://www.learndiary.com/archives/diaries/2910.htm一文中看到的,我想这一点也是很值得注意的,继承时子类的覆盖方法必须显示定义成synchronized。(但是如果使用继承开发环境的话,会默认加上synchronized关键字)

两种方式效率比较:

1、同步块,代码如下:

  1. <span style="font-size:18px;">package com.bjtest.belen;  
  2. import java.util.concurrent.CountDownLatch;  
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. public class TestSynchronized {  
  7.   
  8.         /** 
  9.          * @param args 
  10.          */  
  11.         public static void main(String[] args) {  
  12.               
  13.             ExecutorService service = Executors.newCachedThreadPool();  
  14.             final CountDownLatch cdOrder = new CountDownLatch(1);  
  15.             final CountDownLatch cdAnswer = new CountDownLatch(3);  
  16.               
  17.             final SynchonizedClass sc = new SynchonizedClass();  
  18.             for(int i=0; i<3; i++){  
  19.                 Runnable runnable = new Runnable(){  
  20.   
  21.                     public void run() {  
  22.                         try{  
  23.                             cdOrder.await();  
  24.                             sc.start();  
  25.                             cdAnswer.countDown();  
  26.                         }catch(Exception e){  
  27.                             e.printStackTrace();  
  28.                         }  
  29.                     }  
  30.                       
  31.                 };  
  32.                 service.execute(runnable);  
  33.             }  
  34.             try{  
  35.                 Thread.sleep((long) (Math.random()*10000));  
  36.                 System.out.println("线程" + Thread.currentThread().getName() +   
  37.                         "发布执行命令");  
  38.                 cdOrder.countDown();  
  39.                 long beginTime = System.currentTimeMillis();  
  40.                 System.out.println("线程" + Thread.currentThread().getName() +   
  41.                 "已经发送命令,正在等待结果");  
  42.                 cdAnswer.await();  
  43.                 System.out.println("线程" + Thread.currentThread().getName() +   
  44.                 "已收到所有响应结果,所用时间为:" + (System.currentTimeMillis()-beginTime));  
  45.             }catch(Exception e){  
  46.                 e.printStackTrace();  
  47.             }  
  48.             service.shutdown();  
  49.     }  
  50. }  
  51.   
  52. class SynchonizedClass{  
  53.       
  54.     public void start() throws InterruptedException{  
  55.           
  56.         Thread.sleep(100);//执行其它逻辑消耗时间   
  57.         synchronized(this){  
  58.          System.out.println("我运行使用了 10 ms");  
  59.         }  
  60.     }  
  61. }  
  62. </span>  


运行结果如下:

线程main发布执行命令
线程main已经发送命令,正在等待结果
我运行使用了 10 ms
我运行使用了 10 ms
我运行使用了 10 ms
线程main已收到所有响应结果,所用时间为:110

 

同步方法,代码如下:

  1. <span style="font-size:18px;">package com.bjtest.belen;  
  2. import java.util.concurrent.CountDownLatch;  
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. public class TestSynchronized {  
  7.   
  8.         /** 
  9.          * @param args 
  10.          */  
  11.         public static void main(String[] args) {  
  12.               
  13.             ExecutorService service = Executors.newCachedThreadPool();  
  14.             final CountDownLatch cdOrder = new CountDownLatch(1);  
  15.             final CountDownLatch cdAnswer = new CountDownLatch(3);  
  16.               
  17.             final SynchonizedClass sc = new SynchonizedClass();  
  18.             for(int i=0; i<3; i++){  
  19.                 Runnable runnable = new Runnable(){  
  20.   
  21.                     public void run() {  
  22.                         try{  
  23.                             cdOrder.await();  
  24.                             sc.start();  
  25.                             cdAnswer.countDown();  
  26.                         }catch(Exception e){  
  27.                             e.printStackTrace();  
  28.                         }  
  29.                     }  
  30.                       
  31.                 };  
  32.                 service.execute(runnable);  
  33.             }  
  34.             try{  
  35.                 Thread.sleep((long) (Math.random()*10000));  
  36.                 System.out.println("线程" + Thread.currentThread().getName() +   
  37.                         "发布执行命令");  
  38.                 cdOrder.countDown();  
  39.                 long beginTime = System.currentTimeMillis();  
  40.                 System.out.println("线程" + Thread.currentThread().getName() +   
  41.                 "已经发送命令,正在等待结果");  
  42.                 cdAnswer.await();  
  43.                 System.out.println("线程" + Thread.currentThread().getName() +   
  44.                 "已收到所有响应结果,所用时间为:" + (System.currentTimeMillis()-beginTime));  
  45.             }catch(Exception e){  
  46.                 e.printStackTrace();  
  47.             }  
  48.             service.shutdown();  
  49.     }  
  50. }  
  51.   
  52. class SynchonizedClass{  
  53.       
  54.     public synchronized void start() throws InterruptedException{  
  55.           
  56.         Thread.sleep(100);//执行其它逻辑消耗时间   
  57. //      synchronized(this){   
  58.          System.out.println("我运行使用了 10 ms");  
  59. //      }   
  60.     }  
  61. }  
  62. </span>  

运行结果如下:

线程main发布执行命令
线程main已经发送命令,正在等待结果
我运行使用了 10 ms
我运行使用了 10 ms
我运行使用了 10 ms
线程main已收到所有响应结果,所用时间为:332

两者相差:222ms。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics