当前位置: 首页 > 编程笔记 >

Java类锁、对象锁、私有锁冲突测试

宫亦
2023-03-14
本文向大家介绍Java类锁、对象锁、私有锁冲突测试,包括了Java类锁、对象锁、私有锁冲突测试的使用技巧和注意事项,需要的朋友参考一下

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

一、相关约定

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

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

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

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

二、测试代码

1.编写一个启动类ObjectLock


public class ObjectLock {

 public static void main(String[] args) {

  System.out.println("start time = " + System.currentTimeMillis()+"ms");

  LockTestClass test = new LockTestClass();

  for (int i = 0; i < 3; i++) {

   Thread thread = new ObjThread(test, i);

   thread.start();

  }

 }

}

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


public class ObjThread extends Thread {

 LockTestClass lock;

 int i = 0;

 public ObjThread(LockTestClass lock, int i) {   this.lock = lock;   this.i = i;  }

 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.increment();  } }

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


public class LockTestClass {

 //用于类锁计数

 private static int i = 0;

    //私有锁

 private Object object = new Object();

 /**   * &lt;p&gt;   * 无锁方法   *   * @param threadID   * @param thread   */  public void noSynMethod(long threadID, ObjThread thread) {   System.out.println("nosyn: class obj is " + thread + ", threadId is"     + threadID);  }

 /**   * 对象锁方法1   */  public synchronized void synOnMethod() {   System.out.println("synOnMethod begins" + ", time = "     + System.currentTimeMillis() + "ms");   try {    Thread.sleep(2000L);   } catch (InterruptedException e) {    e.printStackTrace();   }   System.out.println("synOnMethod ends");  }

 /**   * 对象锁方法2,采用synchronized (this)来加锁   */  public void synInMethod() {   synchronized (this) {    System.out.println("synInMethod begins" + ", time = "      + System.currentTimeMillis() + "ms");    try {     Thread.sleep(2000L);    } catch (InterruptedException e) {     e.printStackTrace();    }    System.out.println("synInMethod ends");   }

 }

 /**   * 对象锁方法3   */  public void synMethodWithObj() {   synchronized (object) {    System.out.println("synMethodWithObj begins" + ", time = "      + System.currentTimeMillis() + "ms");    try {     Thread.sleep(2000L);    } catch (InterruptedException e) {     e.printStackTrace();    }    System.out.println("synMethodWithObj ends");   }  }

 /**   * 类锁   */  public static synchronized void increament() {   System.out.println("class synchronized. i = " + i + ", time = "     + System.currentTimeMillis() + "ms");   i++;   try {    Thread.sleep(2000L);   } catch (InterruptedException e) {    e.printStackTrace();   }    System.out.println("class synchronized ends.");  }

}

三、测试结果

1.测试类锁和对象锁,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 = 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方法修改如下:


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 = 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)都是对当前对象加锁,二者的加锁方法够成了竞争关系,同一时刻只能有一个方法能执行。

 类似资料:
  • 我在许多关于可重入锁的教程中看到,它们创建一个新的可重入锁并注入资源,可重入锁的锁定和解锁在try/finally块中调用。我不理解这个锁和线程中使用的资源之间的连接。下面是一个关于可重入锁的教程示例 资源代码 线程声明代码中使用的资源 有人能解释一下,这是如何防止多个线程同时访问给定的资源,从而导致争用情况的???这个可重入锁是在资源中创建对象级锁还是类级锁???

  • 问题内容: 在阅读有关同步的内容时,我遇到了“监视器模式”以封装可变状态。 以下是示例代码 } 用私有锁代替固有锁更好吗? 问题答案: 是的-这意味着您可以看到 所有可能获得该锁的代码 (不考虑反射的可能性)。 如果您锁定(这是我假设您通过“固有锁定”所指的),那么其他代码可以做到: 该代码可能与自己的代码相距很远,并且可能调用其他方法,这些方法又将监视器带走。在这里很容易陷入死锁领域,因为您不容

  • 问题内容: 我在这里思考:如果您有2个线程执行需要同步的FAST操作,那么非阻塞方法不是比阻塞/上下文切换方法更快/更好的方法吗? 非阻塞的意思是: while(true){如果(checkAndGetTheLock())中断;} 如果您有太多线程在锁中循环,我唯一想到的就是饥饿(CPU耗尽)。 如何平衡一种方法与另一种方法? 问题答案: 以下是 Java Concurrency in Pract

  • 在示例代码中 在这个页面上, lock1和lock2分别控制c1和c2上的更新。 然而, 正在获取对象lock1的锁并在同步块时释放它 被执行。 当这个代码块被执行时,这个对象的成员c1上可能还有一个更新——我看不出这个更新是如何被代码中的lock1上的同步所阻止的。 只有对象lock1可以独占访问——除此之外别无它物(?) 那么,实施情况如何 在上面的代码中不同于 甚至 当c1是一个对象而不是一

  • 假设我有两条线。Thread1正在访问一个同步方法,同时,Thread2正在访问同一对象的另一个同步方法。据我所知,Thread2应该等到Thread1完成它的任务。我的问题是,Thread2是否在对象的等待线程列表中?对我来说似乎是这样,但Thread2不调用wait()方法,那么作为逻辑结果,它不应该在对象的等待线程列表中。如果它不在对象的等待线程列表中,那么Thread2的状态是什么?

  • 为什么java可重入锁不会导致死锁?