java并发编程实践学习---java的类锁和对象锁
最近在看Java Concurrent in Practice(java并发编程实践),发现自己对java的线程、锁等机制,理解很肤浅,学习的也不够全面。打算借着这本书,全面的学习下JDK的并发包和一些线程相关的理论知识,填补自己的空白,也可以和大家交流,理解不正确的地方,欢迎指正。第一篇博客,先简单的介绍下类锁和对象锁的概念,和关键字synchronized。
对象锁:java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,方法抛异常的时候,锁仍然可以由JVM来自动释放。
类锁:对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。我们都知道,java类可能会有很多个对象,但是只有1个Class对象,也就是说类的不同实例之间共享该类的Class对象。Class对象其实也仅仅是1个java对象,只不过有点特殊而已。由于每个java对象都有1个互斥锁,而类的静态方法是需要Class对象。所以所谓的类锁,不过是Class对象的锁而已。获取类的Class对象有好几种,最简单的就是MyClass.class的方式。
为什么需要加锁呢?肯定是因为存在不同线程对共享对象的并发访问,没有数据共享就不需要锁。
下面这个类,是我们使用java的synchronized方式进行控制的方法,会在我们后面的线程中调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
package net.aty.lock.target;
public class TargetMethod
{
// 对象锁:形式1
public synchronized void objLockMethod1()
{
System.out.println( "in...objLockMethod1" );
try
{
Thread.sleep( 500 );
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println( "out...objLockMethod1" );
}
// 对象锁:形式2
public void objLockMethod2()
{
synchronized ( this )
{
System.out.println( "in...objLockMethod2" );
try
{
Thread.sleep( 500 );
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println( "out...objLockMethod2" );
}
}
// 类锁:形式1
public static synchronized void classLock1()
{
System.out.println( "classLock1------in" );
try
{
Thread.sleep( 500 );
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println( "classLock1------out" );
}
// 类锁:形式2
public void classLock2()
{
synchronized (TargetMethod. class )
{
System.out.println( "classLock2------in" );
try
{
Thread.sleep( 500 );
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println( "classLock2------out" );
}
}
}
|
1、我们先来做第一个测试,该测试很简单,说明:如果线程不存在数据共享,锁就不会有效果,也就没有必要加锁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.aty.lock.thread.first;
import net.aty.lock.target.TargetMethod;
public class DemoThread1 extends Thread
{
private TargetMethod target = null ;
public DemoThread1(TargetMethod target)
{
this .target = target;
}
@Override
public void run()
{
target.objLockMethod1();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.aty.lock.thread.first;
import net.aty.lock.target.TargetMethod;
public class DemoThread2 extends Thread
{
private TargetMethod target = null ;
public DemoThread2(TargetMethod target)
{
this .target = target;
}
@Override
public void run()
{
target.objLockMethod2();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package net.aty.lock.thread.first;
import net.aty.lock.target.TargetMethod;
public class Test
{
public static void main(String[] args) throws Exception
{
test2();
}
public static void test1() throws Exception
{
TargetMethod target1 = new TargetMethod();
TargetMethod target2 = new TargetMethod();
// 线程1运行后,睡眠500ms
Thread t1 = new DemoThread1(target1);
t1.start();
// 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态
Thread.sleep( 100 );
System.out.println( "main thread runnig...." );
// 线程2开始运行
Thread t2 = new DemoThread2(target2);
t2.start();
}
public static void test2() throws Exception
{
TargetMethod shared = new TargetMethod();
Thread t1 = new DemoThread1(shared);
t1.start();
Thread.sleep( 100 );
System.out.println( "main thread runnig...." );
Thread t2 = new DemoThread2(shared);
t2.start();
}
}
|
2、第二组测试,验证所谓的"类锁"的确可以达到控制静态方法同步的效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package net.aty.lock.thread.second;
import net.aty.lock.target.TargetMethod;
public class DemoThread3 extends Thread
{
public DemoThread3()
{
}
@Override
public void run()
{
TargetMethod.classLock1();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.aty.lock.thread.second;
import net.aty.lock.target.TargetMethod;
public class DemoThread4 extends Thread
{
private TargetMethod target = null ;
public DemoThread4(TargetMethod target)
{
this .target = target;
}
@Override
public void run()
{
target.classLock2();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package net.aty.lock.thread.second;
import net.aty.lock.target.TargetMethod;
public class Test
{
public static void main(String[] args) throws Exception
{
// 线程3运行后,睡眠500ms
Thread t1 = new DemoThread3();
t1.start();
// 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态
Thread.sleep( 100 );
System.out.println( "main thread runnig...." );
// 线程4开始运行
Thread t2 = new DemoThread4( new TargetMethod());
t2.start();
}
}
|
执行结果如下:通过分析,可以知道的确实现了static方法之间的同步访问
classLock1------in
main thread runnig....
classLock1------out
classLock2------in
classLock2------out
3、最后我们来测试下对象锁和类锁的区别和联系。线程5会访问同步的实例方法,线程6访问同步的静态方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.aty.lock.thread.third;
import net.aty.lock.target.TargetMethod;
public class DemoThread5 extends Thread
{
private TargetMethod target = null ;
public DemoThread5(TargetMethod target)
{
this .target = target;
}
@Override
public void run()
{
target.objLockMethod1();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package net.aty.lock.thread.third;
import net.aty.lock.target.TargetMethod;
public class DemoThread6 extends Thread
{
public DemoThread6()
{
}
@Override
public void run()
{
TargetMethod.classLock1();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
package net.aty.lock.thread.third;
import net.aty.lock.target.TargetMethod;
public class Test
{
public static void main(String[] args) throws Exception
{
test2();
}
public static void test1() throws Exception
{
// 线程5开始运行
Thread t1 = new DemoThread5( new TargetMethod());
t1.start();
// 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态
Thread.sleep( 100 );
System.out.println( "main thread runnig...." );
// 线程6运行后,睡眠500ms
Thread t2 = new DemoThread6();
t2.start();
}
public static void test2() throws Exception
{
// 线程6开始运行
Thread t2 = new DemoThread6();
t2.start();
// 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态
Thread.sleep( 100 );
System.out.println( "main thread runnig...." );
// 线程5
Thread t1 = new DemoThread5( new TargetMethod());
t1.start();
}
}
|
执行结果如下:
classLock1------in
main thread runnig....
in...objLockMethod1
classLock1------out
out...objLockMethod1
可以看出,类锁和对象锁不是同1个东西,一个是类的Class对象的锁,1个是类的实例的锁。也就是说:1个线程访问静态synchronized的时候,允许另一个线程访问对象的实例synchronized方法。反过来也是成立的,因为他们需要的锁是不同的。
java并发编程实践学习---java的类锁和对象锁相关推荐
- 【Java并发编程】Java多线程(四):FutureTask 源码分析
前言:[Java并发编程]Java多线程(三):Runnable.Callable --创建任务的方式 在上一篇文章的末尾我们通过两个问题,引出了 FutureTask 及其设计思路,先来回顾一下: ...
- 视频教程-Java并发编程实战-Java
Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...
- java并发编程(三十五)——公平与非公平锁实战
前言 在 java并发编程(十六)--锁的七大分类及特点 一文中我们对锁有各个维度的分类,其中有一个维度是公平/非公平,本文我们来探讨下公平与非公平锁. 公平|非公平 首先,我们来看下什么是公平锁和非 ...
- java并发编程学习juc工具类之Executors
文章目录 Executors 重要方法 1.newCachedThreadPool 2.newFixedThreadPool 3.newScheduledThreadPool 示例代码 4.newSi ...
- 【Java并发编程】java高并发的解决方案(一)
对于我们开发的网站,如果网站的访问量非常大的话,我们就需要考虑相关的并发访问问题了.而且并发问题也是中高级工程师面试中必问的问题,今天我们就来系统学习一下. 为了更好的理解并发和同步,我们先学习两个重 ...
- 【Java并发编程】java并发框架Executor学习笔记
Java SE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程.Executor在客户端和执行任务之间提供了一个间接层,Exe ...
- Java并发编程:Java内存模型JMM
简介 Java内存模型英文叫做(Java Memory Model),简称为JMM.Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各种硬件和系统的内存访问差异,实现平台无关性. CPU和缓存一 ...
- Java 并发编程之同步工具类闭锁 CountDownLatch
Java 同步工具类CountDownLatch相当于一个计数器,假设一个方法,等待一个计数器从初始值5变为0,每使用一次countdown()方法,计数器的值减少1,当计数器的值为0时,触发某件事. ...
- java并发编程(二十六)——单例模式的双重检查锁模式为什么必须加 volatile?
前言 本文我们从一个问题出发来进行探究关于volatile的应用. 问题:单例模式的双重检查锁模式为什么必须加 volatile? 什么是单例模式 单例模式指的是,保证一个类只有一个实例,并且提供一个 ...
最新文章
- No identifier specified for entity
- WebAPi接口安全之公钥私钥加密
- quartz持久化是指_面试必问:Redis 持久化是如何做的?RDB 和 AOF 对比分析
- 将计算机退出域 脚本
- 信号与系统 chapter13 阶跃响应的定义与求法
- linux install StarDict
- 大地win11 64位旗舰版系统v2021.08
- WordPress 简洁好看hankin透明主题
- Scikit-Learn 新版本发布!一行代码秒升级
- python 近期用到的基础知识汇总(主要是skimage的相关矩阵变化函数)(二)
- oracle 942错误(exp imp 出问题的解决方案)
- LitePal(版本1.5.0,写此博客时是最新版本)
- 软考历程(4)——安全问题之病毒
- 遥感数字图像处理复习(朱文泉)
- virutalbox 无线网卡桥接
- Apollo学习笔记(一):canbus模块与车辆底盘之间的CAN数据传输过程
- 利用QQ邮箱设置个性域名邮箱,并在网易邮箱大师客户端添加域名邮箱
- 11. 符号和符号解析
- osg导入模型时,模型全黑的原因及解决方法分析
- 显卡、显卡驱动、Nvcc、Cuda Driver、CudaToolkit 、Cudnn到底是什么?