`

Java类锁和对象锁实践

    博客分类:
  • Java
 
阅读更多

一、前言

     之前对类锁和对象锁是否是互斥的不是太确定,因此决定编写相关的程序进行实践一下。编写前对相关定义约定约定如下:

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

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

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

 

二、测试代码。

    1.编写一个启动类ObjectLock

package com.zjh.blog.practice.basic;

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方法可能会调整以进行不同的测试)

package com.zjh.blog.practice.basic;

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,包括各种加锁方法

 

package com.zjh.blog.practice.basic;

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

 

四、参考:

http://blog.csdn.net/zwan0518/article/details/8725704

 

 

 

 

分享到:
评论

相关推荐

    synchronized枷锁实例

    在Java编程语言中,`synchronized`...理解类锁、对象锁和方法锁的用法,以及它们之间的关系,对于编写高效、安全的多线程Java程序至关重要。通过SynchronizedDemo这个示例代码,我们可以进一步学习和实践这些概念。

    JAVA对象模块.rar

    Java对象模块是Java编程中的核心概念,它代表了程序中的数据和行为的组合。...易语言JAVA对象模块源码可能包含了一些具体实现,深入研究这些源码有助于深化对Java对象模型的理解,并学习到实际开发中的技巧和最佳实践。

    JAVA并发编程实践

    根据给定文件的信息“JAVA并发编程实践”以及其描述为“Java并发学习资料”,我们可以从中提炼出关于Java并发编程的一些核心知识点。Java并发编程是Java高级特性之一,它允许开发者编写能够同时执行多个任务的程序,...

    java文件锁的实现

    Java提供了多种方法来实现文件锁,主要通过`java.nio.channels.FileLock`类来实现。以下是一些关键概念和步骤: 1. **使用FileChannel**:文件锁是与`FileChannel`紧密相关的。`FileChannel`可以从`FileInputStream...

    java多线程和锁,用于学习参考

    Java中的锁分为内置锁(也叫监视器锁)和显式锁。内置锁是通过`synchronized`关键字实现的,它具有自动获取和释放锁的能力,能防止多个线程同时访问同一块代码,确保线程安全。同步方法和同步代码块是`synchronized`...

    java调用Oracle的锁表命令

    在Java中,我们使用`Connection`对象的`setAutoCommit(false)`来开启手动事务管理。在执行完所有操作后,再通过`commit()`提交事务或`rollback()`回滚事务。例如: ```java connection.setAutoCommit(false); //...

    java并发编程实践

    `synchronized`关键字用于实现同步代码块或同步方法,可以指定对象锁或类锁来控制对共享资源的访问。 ##### 3.2 volatile变量 `volatile`关键字用于修饰变量,能够保证该变量对所有线程的可见性,即一旦某个线程...

    Java语言面向对象高级程序设计

    Java语言面向对象高级程序设计是计算机科学中的一个重要领域,它主要...这些知识点构成了Java面向对象高级程序设计的核心内容,学习者通过深入理解和实践,可以提升Java编程的技能,为软件开发和系统设计打下坚实基础。

    java线程与并发编程实践

    Java线程与并发编程实践是Java开发者必备的技能之一,特别是在多核处理器和高并发应用环境中,有效地管理和利用线程能极大地提升程序的性能。本书《java线程与并发实践编程》由Jeff Friesen撰写,2017年2月出版,...

    java并发编程实践(第一版)

    《Java并发编程实践》是关于Java语言在并发编程领域的实践指南,作者在本书中详细介绍了在Java编程中,如何高效地实现多线程程序的设计和开发。本书不仅为初学者提供了理论基础,还为有经验的开发者提供了优化并发...

    27道顶尖的Java多线程、锁、内存模型面试题!.pdf

    当线程试图进入被synchronized修饰的代码块或方法时,会尝试获取对象锁。如果当前线程已经持有该锁,计数器加1;执行完后,计数器减1,当计数器为0时,锁被释放。如果无法获取锁,线程会被阻塞直到锁被其他线程释放...

    java常用锁使用demo工程

    "java常用锁使用demo工程"是一个实践项目,旨在帮助开发者理解并熟练掌握Java中的锁机制。在这个工程中,我们可能会看到各种锁的实例,如内置锁(synchronized)、显式锁(java.util.concurrent.locks包中的Lock接口...

    Java并发编程实践高清pdf及源码

    《Java并发编程实践》是一本深入探讨Java多线程编程的经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了Java平台上的并发编程技术,是Java开发...

    Java并发锁简介-动力节点共9页.pdf.zip

    1. ** monitors**: Java中的每个对象都有一个与之关联的监视器锁,当一个线程进入synchronized代码块或方法时,会自动获取该锁,其他线程尝试进入时会被阻塞,直到锁被释放。 2. ** 同步代码块**: 使用`synchronized...

    JAVA并发编程实践.pdf

    根据提供的信息,“JAVA并发编程实践.pdf”这一文档主要聚焦于Java并发编程的实践与应用,这对于希望深入了解并行处理和多线程技术的开发者来说是非常有价值的资源。下面将基于标题和描述中的关键词“JAVA并发编程...

    门禁系统(Java面向对象)

    门禁系统是一个典型的现实世界问题转化为...总之,门禁系统在Java面向对象编程中是一个很好的实践案例,它展示了如何将现实世界的实体和行为转化为计算机程序,以及如何通过面向对象的设计原则和模式来构建复杂系统。

    javaScript和java参考手册

    2. 学习对象和类的概念,理解JavaScript的原型链和Java的类继承。 3. 深入理解函数和方法,特别是JavaScript中的闭包和高阶函数,以及Java中的设计模式。 4. 掌握JavaScript的事件处理和DOM操作,以及Java的异常处理...

    [Java并发编程实践].(Java.Concurrency.in.Practice).Brian.Goetz.英文原版.pdf

    书中介绍了如何使用`ExecutorService`等接口和类。 - **并发集合**:Java提供了多种并发集合类,如`ConcurrentHashMap`等,用于解决多线程环境下数据结构的安全访问问题。 - **CompletableFuture**:这是一个强大的...

Global site tag (gtag.js) - Google Analytics