爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      线程同步详解

      首页 知识中心 软件开发 文章详情页

      线程同步详解

      2024-04-24 08:30:53 阅读次数:49

      object,signal

      我们可以在计算机上运行各种计算机软件程序。每一个运行的程序可能包括多个独立运行的线程(Thread)。 
      线程(Thread)是一份独立运行的程序,有自己专用的运行栈。线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。 
      当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。 
      同步这个词是从英文synchronize(使同时发生)翻译过来的。我也不明白为什么要用这个很容易引起误解的词。既然大家都这么用,咱们也就只好这么将就。 
      线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。
      
      因此,关于线程同步,需要牢牢记住的第一点是:线程同步就是线程排队。同步就是排队。线程同步的目的就是避免线程“同步”执行。这可真是个无聊的绕口令。 
      关于线程同步,需要牢牢记住的第二点是 “共享”这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。 
      关于线程同步,需要牢牢记住的第三点是,只有“变量”才需要同步访问。如果共享的资源是固定不变的,那么就相当于“常量”,线程同时读取常量也不需要同步。至少一个线程修改共享资源,这样的情况下,线程之间就需要同步。 
      关于线程同步,需要牢牢记住的第四点是:多个线程访问共享资源的代码有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。
      
      为了加深理解,下面举几个例子。 
      有两个采购员,他们的工作内容是相同的,都是遵循如下的步骤: 
      (1)到市场上去,寻找并购买有潜力的样品。 
      (2)回到公司,写报告。 
      这两个人的工作内容虽然一样,他们都需要购买样品,他们可能买到同样种类的样品,但是他们绝对不会购买到同一件样品,他们之间没有任何共享资源。所以,他们可以各自进行自己的工作,互不干扰。 
      这两个采购员就相当于两个线程;两个采购员遵循相同的工作步骤,相当于这两个线程执行同一段代码。
      
      下面给这两个采购员增加一个工作步骤。采购员需要根据公司的“布告栏”上面公布的信息,安排自己的工作计划。 
      这两个采购员有可能同时走到布告栏的前面,同时观看布告栏上的信息。这一点问题都没有。因为布告栏是只读的,这两个采购员谁都不会去修改布告栏上写的信息。
      
      下面增加一个角色。一个办公室行政人员这个时候,也走到了布告栏前面,准备修改布告栏上的信息。 
      如果行政人员先到达布告栏,并且正在修改布告栏的内容。两个采购员这个时候,恰好也到了。这两个采购员就必须等待行政人员完成修改之后,才能观看修改后的信息。 
      如果行政人员到达的时候,两个采购员已经在观看布告栏了。那么行政人员需要等待两个采购员把当前信息记录下来之后,才能够写上新的信息。 
      上述这两种情况,行政人员和采购员对布告栏的访问就需要进行同步。因为其中一个线程(行政人员)修改了共享资源(布告栏)。而且我们可以看到,行政人员的工作流程和采购员的工作流程(执行代码)完全不同,但是由于他们访问了同一份可变共享资源(布告栏),所以他们之间需要同步。
      
      同步锁
      
      前面讲了为什么要线程同步,下面我们就来看如何才能线程同步。 
      线程同步的基本实现思路还是比较容易理解的。我们可以给共享资源加一把锁,这把锁只有一把钥匙。哪个线程获取了这把钥匙,才有权利访问该共享资源。 
      生活中,我们也可能会遇到这样的例子。一些超市的外面提供了一些自动储物箱。每个储物箱都有一把锁,一把钥匙。人们可以使用那些带有钥匙的储物箱,把东西放到储物箱里面,把储物箱锁上,然后把钥匙拿走。这样,该储物箱就被锁住了,其他人不能再访问这个储物箱。(当然,真实的储物箱钥匙是可以被人拿走复制的,所以不要把贵重物品放在超市的储物箱里面。于是很多超市都采用了电子密码锁。) 
      线程同步锁这个模型看起来很直观。但是,还有一个严峻的问题没有解决,这个同步锁应该加在哪里? 
      当然是加在共享资源上了。反应快的读者一定会抢先回答。 
      没错,如果可能,我们当然尽量把同步锁加在共享资源上。一些比较完善的共享资源,比如,文件系统,数据库系统等,自身都提供了比较完善的同步锁机制。我们不用另外给这些资源加锁,这些资源自己就有锁。 
      但是,大部分情况下,我们在代码中访问的共享资源都是比较简单的共享对象。这些对象里面没有地方让我们加锁。 
      读者可能会提出建议:为什么不在每一个对象内部都增加一个新的区域,专门用来加锁呢?这种设计理论上当然也是可行的。问题在于,线程同步的情况并不是很普遍。如果因为这小概率事件,在所有对象内部都开辟一块锁空间,将会带来极大的空间浪费。得不偿失。 
      于是,现代的编程语言的设计思路都是把同步锁加在代码段上。确切的说,是把同步锁加在“访问共享资源的代码段”上。这一点一定要记住,同步锁是加在代码段上的。 
      同步锁加在代码段上,就很好地解决了上述的空间浪费问题。但是却增加了模型的复杂度,也增加了我们的理解难度。 
      现在我们就来仔细分析“同步锁加在代码段上”的线程同步模型。 
      首先,我们已经解决了同步锁加在哪里的问题。我们已经确定,同步锁不是加在共享资源上,而是加在访问共享资源的代码段上。 
      其次,我们要解决的问题是,我们应该在代码段上加什么样的锁。这个问题是重点中的重点。这是我们尤其要注意的问题:访问同一份共享资源的不同代码段,应该加上同一个同步锁;如果加的是不同的同步锁,那么根本就起不到同步的作用,没有任何意义。 
      这就是说,同步锁本身也一定是多个线程之间的共享对象。
      
      Java语言的synchronized关键字
      
      为了加深理解,举几个代码段同步的例子。 
      不同语言的同步锁模型都是一样的。只是表达方式有些不同。这里我们以当前最流行的Java语言为例。Java语言里面用synchronized关键字给代码段加锁。整个语法形式表现为 
      synchronized(同步锁) { 
      // 访问共享资源,需要同步的代码段 
      }
      
      这里尤其要注意的就是,同步锁本身一定要是共享的对象。
      
      … f1() {
      
      Object lock1 = new Object(); // 产生一个同步锁
      
      synchronized(lock1){ 
      // 代码段 A 
      // 访问共享资源 resource1 
      // 需要同步 
      } 
      }
      
      上面这段代码没有任何意义。因为那个同步锁是在函数体内部产生的。每个线程调用这段代码的时候,都会产生一个新的同步锁。那么多个线程之间,使用的是不同的同步锁。根本达不到同步的目的。 
      同步代码一定要写成如下的形式,才有意义。
      
      public static final Object lock1 = new Object();
      
      … f1() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 A 
      // 访问共享资源 resource1 
      // 需要同步 
      }
      
      你不一定要把同步锁声明为static或者public,但是你一定要保证相关的同步代码之间,一定要使用同一个同步锁。 
      讲到这里,你一定会好奇,这个同步锁到底是个什么东西。为什么随便声明一个Object对象,就可以作为同步锁? 
      在Java里面,同步锁的概念就是这样的。任何一个Object Reference都可以作为同步锁。我们可以把Object Reference理解为对象在内存分配系统中的内存地址。因此,要保证同步代码段之间使用的是同一个同步锁,我们就要保证这些同步代码段的synchronized关键字使用的是同一个Object Reference,同一个内存地址。这也是为什么我在前面的代码中声明lock1的时候,使用了final关键字,这就是为了保证lock1的Object Reference在整个系统运行过程中都保持不变。 
      一些求知欲强的读者可能想要继续深入了解synchronzied(同步锁)的实际运行机制。Java虚拟机规范中(你可以在google用“JVM Spec”等关键字进行搜索),有对synchronized关键字的详细解释。synchronized会编译成 monitor enter, … monitor exit之类的指令对。Monitor就是实际上的同步锁。每一个Object Reference在概念上都对应一个monitor。 
      这些实现细节问题,并不是理解同步锁模型的关键。我们继续看几个例子,加深对同步锁模型的理解。
      
      public static final Object lock1 = new Object();
      
      … f1() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 A 
      // 访问共享资源 resource1 
      // 需要同步 
      } 
      }
      
      … f2() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 B 
      // 访问共享资源 resource1 
      // 需要同步 
      } 
      }
      
      上述的代码中,代码段A和代码段B就是同步的。因为它们使用的是同一个同步锁lock1。 
      如果有10个线程同时执行代码段A,同时还有20个线程同时执行代码段B,那么这30个线程之间都是要进行同步的。 
      这30个线程都要竞争一个同步锁lock1。同一时刻,只有一个线程能够获得lock1的所有权,只有一个线程可以执行代码段A或者代码段B。其他竞争失败的线程只能暂停运行,进入到该同步锁的就绪(Ready)队列。 
      每一个同步锁下面都挂了几个线程队列,包括就绪(Ready)队列,待召(Waiting)队列等。比如,lock1对应的就绪队列就可以叫做lock1 - ready queue。每个队列里面都可能有多个暂停运行的线程。 
      注意,竞争同步锁失败的线程进入的是该同步锁的就绪(Ready)队列,而不是后面要讲述的待召队列(Waiting Queue,也可以翻译为等待队列)。就绪队列里面的线程总是时刻准备着竞争同步锁,时刻准备着运行。而待召队列里面的线程则只能一直等待,直到等到某个信号的通知之后,才能够转移到就绪队列中,准备运行。 
      成功获取同步锁的线程,执行完同步代码段之后,会释放同步锁。该同步锁的就绪队列中的其他线程就继续下一轮同步锁的竞争。成功者就可以继续运行,失败者还是要乖乖地待在就绪队列中。 
      因此,线程同步是非常耗费资源的一种操作。我们要尽量控制线程同步的代码段范围。同步的代码段范围越小越好。我们用一个名词“同步粒度”来表示同步代码段的范围。 
      同步粒度 
      在Java语言里面,我们可以直接把synchronized关键字直接加在函数的定义上。 
      比如。 
      … synchronized … f1() { 
      // f1 代码段 
      }
      
      这段代码就等价于 
      … f1() { 
      synchronized(this){ // 同步锁就是对象本身 
      // f1 代码段 
      } 
      }
      
      同样的原则适用于静态(static)函数 
      比如。 
      … static synchronized … f1() { 
      // f1 代码段 
      }
      
      这段代码就等价于 
      …static … f1() { 
      synchronized(Class.forName(…)){ // 同步锁是类定义本身 
      // f1 代码段 
      } 
      }
      
      但是,我们要尽量避免这种直接把synchronized加在函数定义上的偷懒做法。因为我们要控制同步粒度。同步的代码段越小越好。synchronized控制的范围越小越好。 
      我们不仅要在缩小同步代码段的长度上下功夫,我们同时还要注意细分同步锁。 
      比如,下面的代码
      
      public static final Object lock1 = new Object();
      
      … f1() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 A 
      // 访问共享资源 resource1 
      // 需要同步 
      } 
      }
      
      … f2() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 B 
      // 访问共享资源 resource1 
      // 需要同步 
      } 
      }
      
      … f3() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 C 
      // 访问共享资源 resource2 
      // 需要同步 
      } 
      }
      
      … f4() {
      
      synchronized(lock1){ // lock1 是公用同步锁 
      // 代码段 D 
      // 访问共享资源 resource2 
      // 需要同步 
      } 
      }
      
      上述的4段同步代码,使用同一个同步锁lock1。所有调用4段代码中任何一段代码的线程,都需要竞争同一个同步锁lock1。 
      我们仔细分析一下,发现这是没有必要的。 
      因为f1()的代码段A和f2()的代码段B访问的共享资源是resource1,f3()的代码段C和f4()的代码段D访问的共享资源是resource2,它们没有必要都竞争同一个同步锁lock1。我们可以增加一个同步锁lock2。f3()和f4()的代码可以修改为: 
      public static final Object lock2 = new Object();
      
      … f3() {
      
      synchronized(lock2){ // lock2 是公用同步锁 
      // 代码段 C 
      // 访问共享资源 resource2 
      // 需要同步 
      } 
      }
      
      … f4() {
      
      synchronized(lock2){ // lock2 是公用同步锁 
      // 代码段 D 
      // 访问共享资源 resource2 
      // 需要同步 
      } 
      }
      
      这样,f1()和f2()就会竞争lock1,而f3()和f4()就会竞争lock2。这样,分开来分别竞争两个锁,就可以大大较少同步锁竞争的概率,从而减少系统的开销。
      
      信号量
      
      同步锁模型只是最简单的同步模型。同一时刻,只有一个线程能够运行同步代码。 
      有的时候,我们希望处理更加复杂的同步模型,比如生产者/消费者模型、读写同步模型等。这种情况下,同步锁模型就不够用了。我们需要一个新的模型。这就是我们要讲述的信号量模型。 
      信号量模型的工作方式如下:线程在运行的过程中,可以主动停下来,等待某个信号量的通知;这时候,该线程就进入到该信号量的待召(Waiting)队列当中;等到通知之后,再继续运行。 
      很多语言里面,同步锁都由专门的对象表示,对象名通常叫Monitor。 
      同样,在很多语言中,信号量通常也有专门的对象名来表示,比如,Mutex,Semphore。 
      信号量模型要比同步锁模型复杂许多。一些系统中,信号量甚至可以跨进程进行同步。另外一些信号量甚至还有计数功能,能够控制同时运行的线程数。 
      我们没有必要考虑那么复杂的模型。所有那些复杂的模型,都是最基本的模型衍生出来的。只要掌握了最基本的信号量模型——“等待/通知”模型,复杂模型也就迎刃而解了。 
      我们还是以Java语言为例。Java语言里面的同步锁和信号量概念都非常模糊,没有专门的对象名词来表示同步锁和信号量,只有两个同步锁相关的关键字——volatile和synchronized。 
      这种模糊虽然导致概念不清,但同时也避免了Monitor、Mutex、Semphore等名词带来的种种误解。我们不必执着于名词之争,可以专注于理解实际的运行原理。 
      在Java语言里面,任何一个Object Reference都可以作为同步锁。同样的道理,任何一个Object Reference也可以作为信号量。 
      Object对象的wait()方法就是等待通知,Object对象的notify()方法就是发出通知。 
      具体调用方法为 
      (1)等待某个信号量的通知 
      public static final Object signal = new Object();
      
      … f1() { 
      synchronized(singal) { // 首先我们要获取这个信号量。这个信号量同时也是一个同步锁
      
      // 只有成功获取了signal这个信号量兼同步锁之后,我们才可能进入这段代码 
      signal.wait(); // 这里要放弃信号量。本线程要进入signal信号量的待召(Waiting)队列
      
      // 可怜。辛辛苦苦争取到手的信号量,就这么被放弃了
      
      // 等到通知之后,从待召(Waiting)队列转到就绪(Ready)队列里面 
      // 转到了就绪队列中,离CPU核心近了一步,就有机会继续执行下面的代码了。 
      // 仍然需要把signal同步锁竞争到手,才能够真正继续执行下面的代码。命苦啊。 
      … 
      } 
      }
      
      需要注意的是,上述代码中的signal.wait()的意思。signal.wait()很容易导致误解。signal.wait()的意思并不是说,signal开始wait,而是说,运行这段代码的当前线程开始wait这个signal对象,即进入signal对象的待召(Waiting)队列。
      
      (2)发出某个信号量的通知 
      … f2() { 
      synchronized(singal) { // 首先,我们同样要获取这个信号量。同时也是一个同步锁。
      
      // 只有成功获取了signal这个信号量兼同步锁之后,我们才可能进入这段代码 
      signal.notify(); // 这里,我们通知signal的待召队列中的某个线程。
      
      // 如果某个线程等到了这个通知,那个线程就会转到就绪队列中 
      // 但是本线程仍然继续拥有signal这个同步锁,本线程仍然继续执行 
      // 嘿嘿,虽然本线程好心通知其他线程, 
      // 但是,本线程可没有那么高风亮节,放弃到手的同步锁 
      // 本线程继续执行下面的代码 
      … 
      } 
      }
      
      需要注意的是,signal.notify()的意思。signal.notify()并不是通知signal这个对象本身。而是通知正在等待signal信号量的其他线程。
      
      以上就是Object的wait()和notify()的基本用法。 
      实际上,wait()还可以定义等待时间,当线程在某信号量的待召队列中,等到足够长的时间,就会等无可等,无需再等,自己就从待召队列转移到就绪队列中了。 
      另外,还有一个notifyAll()方法,表示通知待召队列里面的所有线程。 
      这些细节问题,并不对大局产生影响。
      
      绿色线程
      
      绿色线程(Green Thread)是一个相对于操作系统线程(Native Thread)的概念。 
      操作系统线程(Native Thread)的意思就是,程序里面的线程会真正映射到操作系统的线程,线程的运行和调度都是由操作系统控制的 
      绿色线程(Green Thread)的意思是,程序里面的线程不会真正映射到操作系统的线程,而是由语言运行平台自身来调度。 
      当前版本的Python语言的线程就可以映射到操作系统线程。当前版本的Ruby语言的线程就属于绿色线程,无法映射到操作系统的线程,因此Ruby语言的线程的运行速度比较慢。 
      难道说,绿色线程要比操作系统线程要慢吗?当然不是这样。事实上,情况可能正好相反。Ruby是一个特殊的例子。线程调度器并不是很成熟。 
      目前,线程的流行实现模型就是绿色线程。比如,stackless Python,就引入了更加轻量的绿色线程概念。在线程并发编程方面,无论是运行速度还是并发负载上,都优于Python。 
      另一个更著名的例子就是ErLang(爱立信公司开发的一种开源语言)。 
      ErLang的绿色线程概念非常彻底。ErLang的线程不叫Thread,而是叫做Process。这很容易和进程混淆起来。这里要注意区分一下。 
      ErLang Process之间根本就不需要同步。因为ErLang语言的所有变量都是final的,不允许变量的值发生任何变化。因此根本就不需要同步。 
      final变量的另一个好处就是,对象之间不可能出现交叉引用,不可能构成一种环状的关联,对象之间的关联都是单向的,树状的。因此,内存垃圾回收的算法效率也非常高。这就让ErLang能够达到Soft Real Time(软实时)的效果。这对于一门支持内存垃圾回收的语言来说,可不是一件容易的事情。
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://java123.blog.csdn.net/article/details/6883914,作者:Java高知社区,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:ssh(Spring+Spring mvc+hibernate)——index.jsp

      下一篇:Page Objects模式源码分析,看源码不用卖萌

      相关文章

      2025-04-01 10:28:25

      php脚本关于退出信号的处理 (注册信号函数) 实例pcntl_signal

      php脚本关于退出信号的处理 (注册信号函数) 实例pcntl_signal

      2025-04-01 10:28:25
      php , signal , 信号
      2025-03-26 10:19:19

      检测数据类型的几种方式

      检测数据类型的几种方式

      2025-03-26 10:19:19
      object , 检测 , 类型
      2025-03-10 09:52:33

      【Java】继承

      继承:extends,Java中的一个关键字,专门用来让一个类和另一个类建立父子关系。

      2025-03-10 09:52:33
      object , 子类 , 构造 , 父类 , 继承 , 调用 , 重写
      2025-02-19 09:03:26

      【多线程】pthread_kill用法|判断线程是否在运行

      【多线程】pthread_kill用法|判断线程是否在运行

      2025-02-19 09:03:26
      int , kill , pthread , signal , 线程
      2025-02-17 09:20:29

      【C++】C++对象数组的定义和初始化

      【C++】C++对象数组的定义和初始化

      2025-02-17 09:20:29
      new , object , 对象 , 数组 , 构造函数
      2025-02-12 09:28:28

      初始Python篇(12)—— object类、对象的特殊属性与方法、深拷贝与浅拷贝

      初始Python篇(12)—— object类、对象的特殊属性与方法、深拷贝与浅拷贝

      2025-02-12 09:28:28
      object , 对象 , 属性 , 拷贝 , 方法 , 调用 , 运算
      2025-02-10 08:56:13

      Linux——信号

      信号是Linux系统提供的一种,向指定进程发送特定事件的方式。

      2025-02-10 08:56:13
      include , int , set , signal , 信号 , 函数 , 进程
      2025-01-17 09:06:29

      js 对象循环

      js 对象循环

      2025-01-17 09:06:29
      arr , object , 分析 , 场景 , 解决 , 调用
      2024-12-31 06:01:41

      数据泵expdp导数据库日志显示不完整

      数据泵expdp导数据库日志显示不完整

      2024-12-31 06:01:41
      object , type
      2024-11-25 09:11:55

      关于AttributeError: type object ‘XXX‘ has no attribute ‘XXX‘的问题

      关于AttributeError: type object ‘XXX‘ has no attribute ‘XXX‘的问题

      2024-11-25 09:11:55
      object , type
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5242559

      查看更多

      最新文章

      【Java】继承

      2025-03-10 09:52:33

      【多线程】pthread_kill用法|判断线程是否在运行

      2025-02-19 09:03:26

      【C++】C++对象数组的定义和初始化

      2025-02-17 09:20:29

      初始Python篇(12)—— object类、对象的特殊属性与方法、深拷贝与浅拷贝

      2025-02-12 09:28:28

      C#中的反射入门知识教程(转载)

      2024-08-06 09:37:28

      利用线程消息队列,实现任务队列

      2024-08-06 09:37:28

      查看更多

      热门文章

      定义Student类

      2024-04-17 02:21:24

      C# 托盘程序 实例 双击显示窗体,最小化到托盘

      2024-03-22 07:56:11

      使用Map把sql返回的list《Object》转成需要的实体对象

      2024-04-24 08:30:53

      判断Object中数据类型(已知类型、未知类型))

      2024-06-04 09:12:23

      GridView根据值的变化改变行列样式

      2024-08-06 09:36:58

      Object转换成json的JS代码

      2024-08-06 09:37:28

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      初始Python篇(12)—— object类、对象的特殊属性与方法、深拷贝与浅拷贝

      C#中的反射入门知识教程(转载)

      C# 托盘程序 实例 双击显示窗体,最小化到托盘

      利用线程消息队列,实现任务队列

      GridView根据值的变化改变行列样式

      使用Map把sql返回的list《Object》转成需要的实体对象

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号