我的编程空间,编程开发者的网络收藏夹
学习永远不晚

关于synchronized的参数及其含义

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

关于synchronized的参数及其含义

这个想必大家都不陌生,java里面的重量级锁。用来控制线程安全的。在long And long ,我刚开始接触java的时候 ,我就对这个关键词好奇颇深。尤其是 它的参数,有this的 也有静态变量的。网上对这个参数解释又太过术语话。

例如

作用于方法时,锁住的是对象的实例(this);

当作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在永久带PermGen(jdk1.8则是metaspace),永久带是全局共享的,因此静态方法锁相当于类的一个全局锁,会锁所有调用该方法的线程;

当作用于一个静态类的时候,不管是不是本身内部的静态类,还是别人的静态类,都可以完成锁住的效果(ps 上锁的时候,相当于一群人 拿把锁找个东西上锁

synchronized作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。

这不管是对于初学者,还是老鸟 。都感觉沉长无味。

最近,我的项目涉及到这一块,我对这个方法有了顿悟,写下来 传之后世

我对这个参数的理解是这样的。


synchronized(获取锁的地方){
工作内容
}

是的 ,你们没看错 ()里面的就是一个“获取锁的地方”。{ }里面是工作内容。 他们有这几条关系。

  • 获取锁的地方 和 工作内容 是不必需要 有任何关联的。 可以有关联,但没有关联 也没事
  • 获取锁的地方 :只是一个让synchronized 整体 放置锁的地方,一个“获取锁的地方” 只有一把锁。**
  • 工作内容: 要进行工作的**前提是 synchronized整体,找到一个“获取锁的地方”,在 “获取锁的地方” 获取到了锁, 如果 “获取锁的地方”的锁,已经被别人拿去了,那么就只能等待别人 把锁还给 “获取锁的地方”。然后 再获取锁。
  • synchronized 会使用运行工作内容的前提,必须获取到锁。这个意思呢,就是例如,当前线程synchronized 获取到了objec A的锁,那么其他线程还可以更改 A 进行操作么?。 这个得到分两种情况,如果其他线程代码 是被synchronized 所包裹的,那么只能等 objec A被释放了,才能更改。如果,其他线程代码没有被synchronized包裹,她可以不需要有锁,就可以对objec A进行操作。

解释

先打个比方,我们把 synchronized这个看成一个整体,那么在多线程的时候,就会有很多个 synchronized整体这个整体开始工作的前提是 它可以从 “获取锁的地方”拿到锁。那么他就可以做工作了。如果 想要 “获取锁的地方”的锁,已经被别人拿走了。那么只能等别人把锁换回来,才行。

上面这个还是有点抽象。就这么说吧 在程序运行多线程的,会产生好多synchronized整体。就叫小明,小红,小芳,小花…等。他们现在手中没有锁,只有手中有锁的时候 才可以工作。 现在小明,小红他们来到工作的地方。获取锁的地方就是路边的一棵树::注意现在路边只有这一棵树小红抢先一步将树上的锁拿走了。然后小红工作去了(她的工作 不用和树有关系,她可以砍树,也可以去路边扫地 )。小明,小芳等其他人,因为没地方获取锁(只有一棵树 并且树的锁 已经被小红拿走了)。所以只能在原地等待 ,小红工作做完了 把锁还给树 ,小明,小芳才有机会进行工作。

注意: 上面是路边只有一棵树,如果存在好几颗树的话,那么小明,小红他们就可以同时放置获取锁 一个数对应一个锁,多个树就多个锁。这个对应于类的实例 (实例可以有好多个)

在这里插入图片描述

验证

我们首先定义一个Runnable ,因为 多线程的话 最好还是用Runnable,至于为什么呢?百度去。


  static class LockRunable implements Runnable {
        private int num;
        private LockNormal lockNormal;
        public LockRunable(int num, LockNormal lockNormal) {
            this.num = num;
            this.lockNormal = lockNormal;
        }
        @Override
        public void run() {
            while (true) {

                    if (num <= 0) {
                        break;
                    }
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "    " + num--);

            }
        }
    }

这个类呢 接受一个整数,一个LockNormal我自己定义的类,在run里面呢先对 num进行判断小于等于0的话,就退出,否则减一。 运行一下


  LockNormal lockNormal = new LockNormal();
        LockRunable one = new LockRunable(15, lockNormal);
        new Thread(one).start();
        new Thread(one).start();
        new Thread(one).start();
        new Thread(one).start();
        new Thread(one).start();

在这里插入图片描述

num竟然变成负的了,这是因为 五个线程同时对他进行操作,造成的。要避免这种情况,只能一个线程操作的时候,别的线程就不能操作。

我们给程序加锁试一下。首先定义一个 静态成员,静态成员有一个特点是系统初始化的,全局只有一个实例。就相当于上面的 只有一棵树。


static final transient Object lock = new Object();

对 工作内容加锁


    @Override
        public void run() {
            while (true) {
                synchronized (lock) {
                    if (num <= 0) {
                        break;
                    }
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "    " + num--);
                }
            }
        }
    }

运行

在这里插入图片描述

这次就和预期结果相等了。但是 我们可发现 都是都是同一个线程进行操作的,这是因为 sleep时候不会释放锁,其他线程也无法进行操作

传入实例


    static class LockRunable implements Runnable {

        private int num;

        private LockNormal lockNormal;

        public LockRunable(int num, LockNormal lockNormal) {
            this.num = num;
            this.lockNormal = lockNormal;
        }

        @Override
        public void run() {
            while (true) {
                synchronized (lockNormal) {
                    if (num <= 0) {
                        break;
                    }
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "    " + num--);
                }
            }
        }
    }

结果:

在这里插入图片描述

也是同样的结果,如果 我们传入this的话 运行还是一样的结果。这就是上面树的问题了,不管是传入的实例,还是this本身实例。只有能保证它们本身是唯一的,也就是“获取锁的地方”只有一个,同一时间内只有一个人能成功获取到锁 进行工作。就和锁静态成员是一样的效果如果我们 new 两个Runnable的话,并且传入this实例的话,就会有两个“获取锁的地方” ,可以有两个人同时工作。

总结


synchronized(放锁的地方){
工作内容
}

只要我们保证“获取锁的地方”是唯一的,那么在同一时刻,就只能有一个工作内容会被执行。如果,“获取锁的地方”不是唯一的(一个类new很多实例,锁住this实例,那么同一时刻就会有很多放锁的地方),在同一时刻就会有好多 工作内容被执行。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

关于synchronized的参数及其含义

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

xargs 命令 -I {} 参数的含义及应用

xargs 命令是一个非常好用的 Linux 命令,它可以将管道或标准输入转换成命令行参数,并用这些参数来执行指定的命令。默认情况下, xargs 命令会将输入按照空格、制表符、换行符等符号进行分隔,并将它们作为一组参数传递给指定的命令。如
2023-08-20

关于Python函数的定义和参数

这篇文章主要介绍了关于Python函数的定义和参数,Python中的函数我们可以理解成是一种具有功能的包装块,也就是封装具有某一种功能的代码块,需要的朋友可以参考下
2023-05-17

CNN卷积函数Conv2D()各参数的含义及用法解读

这篇文章主要介绍了CNN卷积函数Conv2D()各参数的含义及用法解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-21

阿里云新增数据库端口的含义及其影响

随着云计算技术的快速发展,阿里云作为国内领先的云计算服务商,为了更好地满足用户的需求,不断提升服务性能,近日,阿里云宣布新增数据库端口。本文将详细介绍这个新增端口的含义以及它可能带来的影响。一、阿里云新增数据库端口的含义数据库端口,是数据库系统与外界通信的通道,也是数据库系统的入口。在阿里云新增数据库端口后,用户
阿里云新增数据库端口的含义及其影响
2023-11-12

阿里云数据库触发主备切换的含义及其重要性

本文主要解释了阿里云数据库触发主备切换的含义及其重要性,同时探讨了触发主备切换的原因和过程,以及其带来的优势和可能存在的问题。主备切换是指在数据库系统中,当主服务器出现故障或性能下降时,自动或手动地将数据库的读写操作转移到备服务器,以保证数据库服务的连续性和可用性。主备切换是一种常见的数据库备份和恢复策略,可以防
阿里云数据库触发主备切换的含义及其重要性
2023-10-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录