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

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

时间: 2024-10-29 02:33:45

Java类锁和对象锁实践的相关文章

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

类锁和对象锁是否会冲突?对象锁和私有锁是否会冲突?通过实例来进行说明. 一.相关约定 为了明确后文的描述,先对本文涉及到的锁的相关定义作如下约定: 1. 类锁:在代码中的方法上加了static和synchronized的锁,或者synchronized(xxx.class)的代码段,如下文中的increament(): 2.对象锁:在代码中的方法上加了synchronized的锁,或者synchronized(this)的代码段,如下文中的synOnMethod()和synInMethod():

[Java] 方法锁、对象锁和类锁的意义和区别

版权声明:请尊重个人劳动成果,转载注明出处,谢谢! 目录(?)[+] 首先的明白Java中锁的机制 synchronized  在修饰代码块的时候需要一个reference对象作为锁的对象.  在修饰方法的时候默认是当前对象作为锁的对象.  在修饰类时候默认是当前类的Class对象作为锁的对象.   线程同步的方法:sychronized.lock.reentrantLock分析 方法锁(synchronized修饰方法时) 通过在方法声明中加入 synchronized关键字来声明 synch

Java 类中类属性和对象属性的初始化顺序

对象 边城狂人 Java 类中类属性 (static 变量) 和对象属性 (非 static 变量) 的初始化顺序可以用如下程序测试: /** * @(#) Test.java * @author fancy */ public class Test { static String a = "string-a"; static String b; String c = "stirng-c"; String d; static { printStatic("

Java中使用synchronized和Lock对象获取对象锁

在并发环境下,解决共享资源冲突问题时,可以考虑使用锁机制. 1.对象的锁 所有对象都自动含有单一的锁. JVM负责跟踪对象被加锁的次数.如果一个对象被解锁,其计数变为0.在任务(线程)第一次给对象加锁的时候,计数变为1.每当这个相同的任务(线程)在此对象上获得锁时,计数会递增. 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁. 每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源. 2.synchronized同步块 2.

Java多线程的同步示例及对象锁机制

java多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问. 下面以一个简单的实例来进行对比分析.实例要完成的工作非常简单,就是创建10个线程,每个线程都打印从0到99这100个数字,我们希望线程之间不会出现交叉乱序打印,而是顺序地打印. 先来看第一段代码,这里我们在run()方法中加入了synchronized关键字,希望能对run方法进行互斥访问,但结果并不如我们希望那样,这 是因为这里synchronized锁住的是this对象,即

详解Java多线程编程中互斥锁ReentrantLock类的用法_java

0.关于互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是

JAVA语言规范-线程和锁章节之同步、等待和通知

原文链接  本文是Oracle官方<Java语言规范>的译文 JAVA语言规范:线程和锁 1 同步 JAVA编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视器.一次仅有一个线程可能在监视器上持有锁.尝试锁住该监视器的任何其他线程被阻塞,直到它们可以再该监视器上获得一个锁.线程t可以多次锁住特别的监视器:每个解锁将一个加锁操作的作用反转来了. synchronized语句计算了一个对象的引用

Java 高并发九:锁的优化和注意事项详解_java

摘要 本系列基于炼数成金课程,为了更好的学习,做了系列的记录. 本文主要介绍: 1. 锁优化的思路和方法 2. 虚拟机内的锁优化 3. 一个错误使用锁的案例 4. ThreadLocal及其源码分析 1. 锁优化的思路和方法 在[高并发Java 一] 前言中有提到并发的级别. 一旦用到锁,就说明这是阻塞式的,所以在并发度上一般来说都会比无锁的情况低一点. 这里提到的锁优化,是指在阻塞式的情况下,如何让性能不要变得太差.但是再怎么优化,一般来说性能都会比无锁的情况差一点. 这里要注意的是,在[高并

Java多线程之内置锁与显示锁

Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算是互有补充,今天就来做一个总结. Synchronized 内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁. synchronized(list){ //获得锁      list.append(); list.count();    }//释放锁   通信 与Synchronized配套使用的通信方法通常有wait(),