类锁和对象锁是否会冲突?对象锁和私有锁是否会冲突?通过实例来进行说明。
一、相关约定
为了明确后文的描述,先对本文涉及到的锁的相关定义作如下约定:
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();/** * <p> * 无锁方法 * * @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可重入锁不会导致死锁?