最近在看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的类锁和对象锁相关推荐

  1. 【Java并发编程】Java多线程(四):FutureTask 源码分析

    前言:[Java并发编程]Java多线程(三):Runnable.Callable --创建任务的方式 在上一篇文章的末尾我们通过两个问题,引出了 FutureTask 及其设计思路,先来回顾一下: ...

  2. 视频教程-Java并发编程实战-Java

    Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...

  3. java并发编程(三十五)——公平与非公平锁实战

    前言 在 java并发编程(十六)--锁的七大分类及特点 一文中我们对锁有各个维度的分类,其中有一个维度是公平/非公平,本文我们来探讨下公平与非公平锁. 公平|非公平 首先,我们来看下什么是公平锁和非 ...

  4. java并发编程学习juc工具类之Executors

    文章目录 Executors 重要方法 1.newCachedThreadPool 2.newFixedThreadPool 3.newScheduledThreadPool 示例代码 4.newSi ...

  5. 【Java并发编程】java高并发的解决方案(一)

    对于我们开发的网站,如果网站的访问量非常大的话,我们就需要考虑相关的并发访问问题了.而且并发问题也是中高级工程师面试中必问的问题,今天我们就来系统学习一下. 为了更好的理解并发和同步,我们先学习两个重 ...

  6. 【Java并发编程】java并发框架Executor学习笔记

    Java SE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程.Executor在客户端和执行任务之间提供了一个间接层,Exe ...

  7. Java并发编程:Java内存模型JMM

    简介 Java内存模型英文叫做(Java Memory Model),简称为JMM.Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各种硬件和系统的内存访问差异,实现平台无关性. CPU和缓存一 ...

  8. Java 并发编程之同步工具类闭锁 CountDownLatch

    Java 同步工具类CountDownLatch相当于一个计数器,假设一个方法,等待一个计数器从初始值5变为0,每使用一次countdown()方法,计数器的值减少1,当计数器的值为0时,触发某件事. ...

  9. java并发编程(二十六)——单例模式的双重检查锁模式为什么必须加 volatile?

    前言 本文我们从一个问题出发来进行探究关于volatile的应用. 问题:单例模式的双重检查锁模式为什么必须加 volatile? 什么是单例模式 单例模式指的是,保证一个类只有一个实例,并且提供一个 ...

最新文章

  1. No identifier specified for entity
  2. WebAPi接口安全之公钥私钥加密
  3. quartz持久化是指_面试必问:Redis 持久化是如何做的?RDB 和 AOF 对比分析
  4. 将计算机退出域 脚本
  5. 信号与系统 chapter13 阶跃响应的定义与求法
  6. linux install StarDict
  7. 大地win11 64位旗舰版系统v2021.08
  8. WordPress 简洁好看hankin透明主题
  9. Scikit-Learn 新版本发布!一行代码秒升级
  10. python 近期用到的基础知识汇总(主要是skimage的相关矩阵变化函数)(二)
  11. oracle 942错误(exp imp 出问题的解决方案)
  12. LitePal(版本1.5.0,写此博客时是最新版本)
  13. 软考历程(4)——安全问题之病毒
  14. 遥感数字图像处理复习(朱文泉)
  15. virutalbox 无线网卡桥接
  16. Apollo学习笔记(一):canbus模块与车辆底盘之间的CAN数据传输过程
  17. 利用QQ邮箱设置个性域名邮箱,并在网易邮箱大师客户端添加域名邮箱
  18. 11. 符号和符号解析
  19. osg导入模型时,模型全黑的原因及解决方法分析
  20. 显卡、显卡驱动、Nvcc、Cuda Driver、CudaToolkit 、Cudnn到底是什么?

热门文章

  1. 我的编程生涯的入门语言 - C语言之学员成绩管理
  2. 2、SharePoint安装篇——之安装Microsoft Office SharePoint Server 2007
  3. 查看关于yum的配置
  4. Django 学习(一)Django安装以及初步使用
  5. 【Python】判断列表中是否存在一个数
  6. [云炬创业管理笔记]第三章打造优秀创业团队讨论2
  7. 云炬60s看世界20211127
  8. python黑色的_python – 将RGB转换为黑色或白色
  9. 空格替换_O(n)方法
  10. 3DSlicer14:Loadable Module