Java类锁、对象锁、私有锁冲突测试
作者:junjie 发布时间:2022-04-25 05:06:22
类锁和对象锁是否会冲突?对象锁和私有锁是否会冲突?通过实例来进行说明。
一、相关约定
为了明确后文的描述,先对本文涉及到的锁的相关定义作如下约定:
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)都是对当前对象加锁,二者的加锁方法够成了竞争关系,同一时刻只能有一个方法能执行。
猜你喜欢
- 一、实现方式@ConfigurationProperties 注解(最好加上前缀prefix=“person”,标明是和配置文件中哪个开头的
- 首先安装consul环境,参照之前的文章:https://www.jb51.net/article/141789.htm项目规划,2个服务端
- 引言Spring Boot的一个便捷功能是外部化配置,可以轻松访问属性文件中定义的属性。本文将详细介绍@ConfigurationPrope
- FPS是什么?FPS (每秒传输帧数(Frames Per Second))【摘自百度百科】FPS是图像领域中的定义,是指画面每秒传输帧数,
- 集合嵌套查询和集合嵌套结果的区别嵌套查询是多条sql语句分开写并配置,嵌套结果是一条sql语句关联查询并配置,实质效果是一样的。嵌套语句的查
- 这篇文章主要介绍了java加载property文件配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,
- 一、Socket是什么Socket 的中文翻译过来就是“套接字”。套接字是什么,我们先来看看它的英文含义:插座。Socket 就像一个电话插
- 一、相关概念1.1 Jenkins概念:Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台。这是一个免费
- 如下所示:import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.
- 问题介绍:用二维数组表示一个迷宫,设置迷宫起点和终点,输出迷宫中的一条通路实现思路:二维数组表示迷宫:0表示路且未走过、1表示墙、2表示通路
- 本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下先是效果图:主菜单:游戏:设置:错误处理:代码:#include
- Eclipse的Servers视图中无法添加Tomcat6/Tomcat7的方法引言: 在基于Eclipse的开发过程中,出现了无法在Ecl
- 概述Spring Cloud中,客户端的负载均衡使用的是Ribbon,Ribbon的超时时间默认很短,需要进行调整。Spring Cloud
- 1. 为什么要更改SpringBoot运行方式?Tomcat Connector(连接器)有三种运行模式:bio nio aprbio(bl
- 本文为大家分享了JAVA语言课程设计:连连看小游戏,供大家参考,具体内容如下1.设计内容界面中有5*10的界面,图中共有6种不同的图片,每两
- 1、pom.xml配置修改<packaging>jar</packaging>//修改为<packaging&
- class文件中的常量池之前我们在讲class文件的结构时,提到了每个class文件都有一个常量池,常量池中存了些什么东西呢?字符串常量,类
- 什么是mybatis,mybatis有什么特点,下面先给大家介绍下mybatis的概念及特点。jdbc开发优缺点:1)优点:简单易学,上手快
- 前言在介绍使用微信自定义分享前,我们来先了解一下什么是自定义分享?访问自定义微信外链地址页面,点击红色框位置进行分享给朋友或者朋友圈,具体操
- Java操作Redis的方式有下面两种:一、jedis(1)maven配置<dependency> <grou