Java类锁和对象锁实践-阿里云开发者社区

开发者社区> ali清英> 正文

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
初识Java神秘成员:String类 | 带你学《Java面向对象编程》之二十六
本节将为读者介绍Java世界必不可少的特殊数据类型:String类。
804 0
Java面向对象高级--匿名内部类
<h1>1、匿名内部类的定义</h1> <p>内部类:在一个类中,还有另外一个类称为内部类。</p> <p>匿名内部类:如果一个类在整个操作中只使用一次的话,就可以将其定义为匿名内部类。匿名内部类实在抽象类和接口的基础上发展起来的。</p> <p></p> <pre name="code" class="java">interface A{ public void printIn
833 0
Java面向对象基础--类的设计及分析问题的方法---用户登录例子
<h1>1、用户登录的示例</h1> <div>首先要做的就是先把功能实现:</div> <div> <pre name="code" class="java">public class LoginDemo01{ public static void main(String args[]){ if(args.length!=2){ // 应该判断输入的参数个数是否是2
1071 0
Java面向对象高级--抽象类的基本概念------abstract
<h1>抽象类的概念:</h1> <p>包含一个抽象方法的类就称为抽象类。</p> <p>抽象方法:只声明但未实现的方法称为抽象方法,使用abstract关键字声明。</p> <h1>抽象类的定义及使用规则:</h1> <div> <img src="http://img.blog.csdn.net/20130925145338703" alt=""><br> </div> <d
1000 0
《21天学通Java(第6版)》—— 1.3 对象和类
面向对象编程是基于现实世界的情况进行建模的,对象由多种更小的对象构成。
1245 0
UML面向对象分析与建模-【4】类图和对象图
一、概述 UML的类图和对象图表达的是对象模型的静态结构方面。 类图描述的是一种静态关系,在系统的整个生命周期都是有效的。通过分析问题域和用例,就可以得到相关的类,然后再把逻辑上相关的类封装成包。
1179 0
Java面向对象高级--抽象类与接口的应用
<h1>1、为抽象类和接口实例化</h1> <div> <img src="http://img.blog.csdn.net/20130928113110421" alt=""><br> </div> <div>抽象类和接口不能直接实例化,因为其内部包含了各个抽象方法,抽象方法本身都是未实现的方法,所以无法调用。通过对象多态性,子类发生了向上转型之后,所调用的全部方法都是被覆写过了的方
1262 0
Java面向对象基础--内部类
<h1>1、什么是内部类?</h1> <div>一个类中还存在另外一个类,则成为内部类。</div> <div> <img src="http://img.blog.csdn.net/20130911184634359" alt=""><br> </div> <div> <pre name="code" class="java">class Outer{ // 定义外部类 pr
897 0
+关注
ali清英
方腾飞,花名清英,英文名kiral,并发编程网创始人,支付宝技术专家,《Java并发编程的艺术》作者。
614
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载