• Java类锁和对象锁实践和内部私有锁关联


    Java类锁和对象锁实践

    感谢[jiehao]同学的投稿,投稿可将文章发送到tengfei@ifeve.com

    类锁和对象锁是否会冲突?对象锁和私有锁是否会冲突?通过实例来进行说明。

    一、相关约定

    为了明确后文的描述,先对本文涉及到的锁的相关定义作如下约定:

    1. 类锁:在代码中的方法上加了static和synchronized的锁,或者synchronized(xxx.class)的代码段,如下文中的increament();

    2.对象锁:在代码中的方法上加了synchronized的锁,或者synchronized(this)的代码段,如下文中的synOnMethod()和synInMethod();

    3.私有锁:在类内部声明一个私有属性如private Object lock,在需要加锁的代码段synchronized(lock),如下文中的synMethodWithObj()。

    二、测试代码

    1.编写一个启动类ObjectLock

    01 public class ObjectLock {
    02     public static void main(String[] args) {
    03         System.out.println("start time = " + System.currentTimeMillis()+"ms");
    04         LockTestClass test = new LockTestClass();
    05         for (int i = 0; i < 3; i++) {
    06             Thread thread = new ObjThread(test, i);
    07             thread.start();
    08         }
    09     }
    10 }

    2.编写一个线程类ObjThread,用于启动同步方法(注意它的run方法可能会调整以进行不同的测试)

    01 public class ObjThread extends Thread {
    02     LockTestClass lock;
    03     int i = 0;
    04  
    05     public ObjThread(LockTestClass lock, int i) {
    06         this.lock = lock;
    07         this.i = i;
    08     }
    09  
    10     public void run() {
    11         //无锁方法
    12 //      lock.noSynMethod(this.getId(),this);
    13         //对象锁方法1,采用synchronized synInMethod的方式
    14         lock.synInMethod();
    15         //对象锁方法2,采用synchronized(this)的方式
    16 //      lock.synOnMethod();
    17         //私有锁方法,采用synchronized(object)的方式
    18 //      lock.synMethodWithObj();
    19         //类锁方法,采用static synchronized increment的方式
    20         LockTestClass.increment();
    21     }
    22 }

    3.再编写一个锁的测试类LockTestClass,包括各种加锁方法

    01 public class LockTestClass {
    02     //用于类锁计数
    03     private static int i = 0;
    04     //私有锁
    05     private Object object = new Object();
    06  
    07     /**
    08      * &lt;p&gt;
    09      * 无锁方法
    10      *
    11      * @param threadID
    12      * @param thread
    13      */
    14     public void noSynMethod(long threadID, ObjThread thread) {
    15         System.out.println("nosyn: class obj is " + thread + ", threadId is"
    16                 + threadID);
    17     }
    18  
    19     /**
    20      * 对象锁方法1
    21      */
    22     public synchronized void synOnMethod() {
    23         System.out.println("synOnMethod begins" + ", time = "
    24                 + System.currentTimeMillis() + "ms");
    25         try {
    26             Thread.sleep(2000L);
    27         } catch (InterruptedException e) {
    28             e.printStackTrace();
    29         }
    30         System.out.println("synOnMethod ends");
    31     }
    32  
    33     /**
    34      * 对象锁方法2,采用synchronized (this)来加锁
    35      */
    36     public void synInMethod() {
    37         synchronized (this) {
    38             System.out.println("synInMethod begins" + ", time = "
    39                     + System.currentTimeMillis() + "ms");
    40             try {
    41                 Thread.sleep(2000L);
    42             } catch (InterruptedException e) {
    43                 e.printStackTrace();
    44             }
    45             System.out.println("synInMethod ends");
    46         }
    47  
    48     }
    49  
    50     /**
    51      * 对象锁方法3
    52      */
    53     public void synMethodWithObj() {
    54         synchronized (object) {
    55             System.out.println("synMethodWithObj begins" + ", time = "
    56                     + System.currentTimeMillis() + "ms");
    57             try {
    58                 Thread.sleep(2000L);
    59             } catch (InterruptedException e) {
    60                 e.printStackTrace();
    61             }
    62             System.out.println("synMethodWithObj ends");
    63         }
    64     }
    65  
    66     /**
    67      * 类锁
    68      */
    69     public static synchronized void increament() {
    70         System.out.println("class synchronized. i = " + i + ", time = "
    71                 + System.currentTimeMillis() + "ms");
    72         i++;
    73         try {
    74             Thread.sleep(2000L);
    75         } catch (InterruptedException e) {
    76             e.printStackTrace();
    77         }
    78          System.out.println("class synchronized ends.");
    79     }
    80  
    81 }

    三、测试结果

    1.测试类锁和对象锁,ObjectThread的run方法修改如下:

    01 public void run() {
    02         //无锁方法
    03 //      lock.noSynMethod(this.getId(),this);
    04         //对象锁方法1,采用synchronized synInMethod的方式
    05         lock.synInMethod();
    06         //对象锁方法2,采用synchronized(this)的方式
    07 //      lock.synOnMethod();
    08         //私有锁方法,采用synchronized(object)的方式
    09 //      lock.synMethodWithObj();
    10         //类锁方法,采用static synchronized increment的方式
    11         LockTestClass.increament();
    12     }

    终端输出:

    start time = 1413101360231ms
    synInMethod begins, time = 1413101360233ms
    synInMethod ends
    class synchronized. i = 0, time = 1413101362233ms
    synInMethod begins, time = 1413101362233ms
    class synchronized ends.
    synInMethod ends
    class synchronized. i = 1, time = 1413101364233ms
    synInMethod begins, time = 1413101364233ms
    class synchronized ends.
    synInMethod ends
    class synchronized. i = 2, time = 1413101366234ms
    class synchronized ends.

    可以看到对象锁方法(synInMothod)第一次启动时比类锁方法(increament)快2秒,这是因为在synInMehtod执行时sleep了2秒再执行的increament,而这两个方法共用一个线程,所以会慢2秒,如果increament在run中放到synInMethod前面,那么第一次启动时就是increament快2秒。 而当类锁方法启动时,另一个线程时的对象锁方法也几乎同时启动,说明二者使用的并非同一个锁,不会产生竞争。 结论:类锁和对象锁不会产生竞争,二者的加锁方法不会相互影响。

    2.私有锁和对象锁,ObjectThread的run方法修改如下:

    01 public void run() {
    02         //无锁方法
    03 //      lock.noSynMethod(this.getId(),this);
    04         //对象锁方法1,采用synchronized synInMethod的方式
    05         lock.synInMethod();
    06         //对象锁方法2,采用synchronized(this)的方式
    07 //      lock.synOnMethod();
    08         //私有锁方法,采用synchronized(object)的方式
    09         lock.synMethodWithObj();
    10         //类锁方法,采用static synchronized increment的方式
    11 //      LockTestClass.increament();
    12     }

    终端输出:

    start time = 1413121912406ms
    synInMethod begins, time = 1413121912407ms.
    synInMethod ends.
    synMethodWithObj begins, time = 1413121914407ms
    synInMethod begins, time = 1413121914407ms.
    synInMethod ends.
    synMethodWithObj ends
    synInMethod begins, time = 1413121916407ms.
    synMethodWithObj begins, time = 1413121916407ms
    synInMethod ends.
    synMethodWithObj ends
    synMethodWithObj begins, time = 1413121918407ms
    synMethodWithObj ends

    和类锁和对象锁非常类似。

    结论:私有锁和对象锁也不会产生竞争,二者的加锁方法不会相互影响。

     
    3.synchronized直接加在方法上和synchronized(this),ObjectThread的run方法修改如下:
    public void run() {
    		//无锁方法
    //		lock.noSynMethod(this.getId(),this);
    		//对象锁方法1,采用synchronized synInMethod的方式
    		lock.synInMethod();
    		//对象锁方法2,采用synchronized(this)的方式
    		lock.synOnMethod();
    		//私有锁方法,采用synchronized(object)的方式
    //		lock.synMethodWithObj();
    		//类锁方法,采用static synchronized increment的方式
    //		LockTestClass.increament();
    	}

    终端输出:

    start time = 1413102913278ms
    synInMethod begins, time = 1413102913279ms
    synInMethod ends
    synInMethod begins, time = 1413102915279ms
    synInMethod ends
    synOnMethod begins, time = 1413102917279ms
    synOnMethod ends
    synInMethod begins, time = 1413102919279ms
    synInMethod ends
    synOnMethod begins, time = 1413102921279ms
    synOnMethod ends
    synOnMethod begins, time = 1413102923279ms
    synOnMethod ends

           可以看到,二者严格地串行输出(当然再次执行时先运行synInMethod还是先运行synOnMethod并不是确定的,取决于谁获得了锁)。

        结论:synchronized直接加在方法上和synchronized(this)都是对当前对象加锁,二者的加锁方法够成了竞争关系,同一时刻只能有一个方法能执行。

  • 相关阅读:
    【NOI2005T1】瑰丽华尔兹-DP单调队列优化
    【POJ1113】Wall-Graham-Scan算法求凸包
    【POJ1113】Wall-Graham-Scan算法求凸包
    【POJ2774】Long Long Message-求最长公共子串(后缀数组求法)
    【POJ2774】Long Long Message-求最长公共子串(后缀数组求法)
    【POJ2195】Going Home-最小费用最大流模板题
    【POJ2195】Going Home-最小费用最大流模板题
    【POJ1273】Drainage Ditches-最大流问题
    【POJ1273】Drainage Ditches-最大流问题
    codevs 1155 金明的预算方案
  • 原文地址:https://www.cnblogs.com/wzhanke/p/4494059.html
Copyright © 2020-2023  润新知