首页 文章 精选 留言 我的

精选列表

搜索[天玑9500],共10000篇文章
优秀的个人博客,低调大师

全球 AI 人才榜单首次曝光,华人撑起半边天

7 月 3 日,2025 全球数字经济大会上,一份重磅榜单面向全球首次揭晓。 该榜单基于近十年近 10 万篇文献深度分析,列出了全球人工智能领域的 Top100 人才。其中,华人依旧拿下了主力席位。 凤凰网科技从中提炼了出了一份较为瞩目的人员名单,这些人现多数就职于国内外企业,仍在人工智能前沿探索领域活跃,包括: 何恺明,曾任职于 AI 殿堂美国麻省理工学院(MIT),作为 ResNet 之父,是深度学习革命的关键推手,其提出的残差学习(Residual Learning)概念,一举攻破了困扰神经网络多年的“梯度消失”难题,让深达千层的网络训练成为可能。其论文引用数以骇人的数十万次傲视群雄(公开数据约 40 万 +),被誉为“CV 界的诺奖级工作”。6 月 26 日,何恺明刚刚官宣入职 GoogleDeepMind,担任杰出科学家,同时还保留了 MIT 终身副教授身份。 张祥雨,曾是旷视研究院的顶梁柱,现已入职阶跃星辰任首席科学家; 2016 年,以 ResNet(作为核心贡献者之一)问鼎 CVPR 最佳论文,震动世界!随后在 ImageNet、COCO 等视觉“奥林匹克”赛场多次屠榜。其与团队开创的 ResNet、ShuffleNet 系列影响颇深,Google Scholar 引用逾 40,000 次,是无数手机、摄像头、自动驾驶系统的“核心引擎”。 任少卿,蔚来汽车自动驾驶的灵魂人物,计算机视觉与自动驾驶融合领域的顶尖专家,曾发表多篇极具影响力的 CV 顶会论文。 田奇,华为在人工智能领域的重要人物,也是华为计算产品线(昇腾 AI 处理器等)和 MindSpore 框架背后的核心操盘手。 王云鹤,华为诺亚方舟实验室的研究员。专注于 AI 基础模型、神经网络架构搜索(NAS)、模型轻量化等前沿方向,是华为 AI“顶天”(前沿)又“立地”(落地)战略的重要实践者。 谢凌曦,华为天才少年,在计算机视觉,特别是视觉大模型、自监督学习、对抗鲁棒性等领域有系列开创性工作。 王晓刚,商汤科技联合创始人、核心技术奠基人之一。在商汤,他主导了核心视觉算法框架的构建。 石建萍,商汤科技自动驾驶研发团队的领军女将。带领团队在智能驾驶视觉感知、多传感器融合、高精定位等方面取得突破性进展。 闫俊杰,MiniMax 创始人,国内最早一批成立的大模型公司核心人物。 曹越,前微软杰出工程师,现Sand.AI创始人兼 CEO。专注打造下一代 AI 智能体(AI Agent)平台。 陶大程,新加坡南洋理工大学(NTU)协理副校长、澳大利亚桂冠教授,视觉大牛,IEEE / AAAS / ACM 三料 Fellow,曾任京东探索研究院院长(2023 年卸任)。研究横跨计算机视觉、机器学习、统计学习、可信 AI(鲁棒性、可解释性、公平性)等核心领域。 刘子纬,新加坡南洋理工大学(NTU)新锐实力派教授,学术明星。在视觉-语言理解(VLP)、多模态大模型、信息检索方向成果斐然。其工作多次发表于 CVPR, ICCV, NeurIPS 等顶会,并常居排行榜前列,是推动多模态预训练模型发展与应用的重要力量。 贾佳亚,香港中文大学计算机科学与工程系教授,思谋科技创始人。著名计算机视觉学者,专注于底层视觉重建、图像增强、图像分割、医学图像分析等方向。 杨明玄,美国加州大学默塞德分校(UC Merced)计算机科学教授,Google DeepMind 研究员。深耕机器学习和数据挖掘领域,特别是在图神经网络(GNN)、推荐系统、社交网络分析等方面有突出建树。 刘威,前腾讯混元大模型技术负责人之一,腾讯杰出科学家,2025 年初离职创业。2024 年领导开源混元文生图模型、3D 生成模型“Hunyuan3D-1.0”,推动腾讯内部 700 + 业务接入 AI 能力(如微信输入法、腾讯会议)。发表顶会论文 100 + 篇,总引用 3600 + 次,获 CVPR 青年研究者奖、SIGIR 最佳论文荣誉奖。 颜水成,新加坡国立大学终身教授,培养 50 + 名博士,建立亚太最大计算机视觉实验室,历任 360 首席科学家、依图 CTO、Sea 集团 AI Lab 主任;2023 年加入昆仑万维任 2050 全球研究院院长,2024 年底卸任。 据东壁科技数据创始人、深圳大学特聘教授吴登生介绍,该报告基于东壁全球科技文献数据平台(dbdata.com),对全球 AI 研究生态进行系统分析,数据集涵盖近 20 万名来自 175 个国家和地区、3847 个机构的学者,时间跨度为 2015 至 2024 年。 值得一提的是,何恺明、刘子纬、王晓刚、陶大程均师承中国人工智能先驱、商汤科技创始人汤晓鸥,张祥雨曾师从何恺明。

优秀的个人博客,低调大师

熬夜7天吐血整理,适合Vue用户的React详细教程

我的日常工作中使用的是Vue,对于React只是做过简单的了解,并没有做过深入学习。趁着假期,我决定好好学一学React,今天这篇文章就是我在学习React之后,将React与Vue的用法做的一个对比,通过这个对比,方便使用Vue的小伙伴可以快速将Vue中的写法转换为React的写法。 插槽,在React中没找到?? 在使用Vue的时候,插槽是一个特别常用的功能,通过定义插槽,可以在调用组件的时候将外部的内容传入到组件内部,显示到指定的位置。在Vue中,插槽分为默认插槽,具名插槽和作用域插槽。其实不仅仅Vue,在React中其实也有类似插槽的功能,只是名字不叫做插槽,下面我将通过举例来说明。 默认插槽 现在项目需要开发一个卡片组件,如下图所示,卡片可以指定标题,然后卡片内容可以用户自定义,这时候对于卡片内容来说,就可以使用插槽来实现,下面我们就分别使用Vue和React来实现这个功能 Vue实现 首先实现一个card组件,如下代码所示 <template> <div class="card"> <div class="card__title"> <span>{{ title }}</span> </div> <div class="card__body"> <slot></slot> </div> </div> </template> <script> export default { props: { title: { type: String, default: '' } } } </script> 可以看到上面我们使用了<slot></slot>,这个就是组件的默认插槽,在使用组件的时候,传入的内容将会被放到<slot></slot>所在位置 在外部使用定义的card组件 <template> <div> <my-card> <div>我将被放在card组件的默认插槽里面</div> </my-card> </div> </template> <script> import MyCard from '../components/card' export default { components: { MyCard } } </script> 如上代码,就可以使用组件的默认插槽将外部的内容应用到组件里面指定的位置了。 React实现 虽然在React里面没有插槽的概念,但是React里面也可以通过props.children拿到组件标签内部的子元素的,就像上面代码<my-card>标签内的子元素,通过这个我们也可以实现类似Vue默认插槽的功能,一起看看代码。 使用React定义Card组件 import React from 'react' export interface CardProps { title: string, children: React.ReactNode } export default function(props: CardProps) { return ( <div className="card"> <div className="card__title"> <span>{props.title}</span> </div> <div className="card__body"> {/**每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容 */} {props.children} </div> </div> ); } 在外部使用Card组件 import React from 'react' import Card from './components/Card' export default function () { return ( <div> <Card title="标题"> <div>我将被放在card组件的body区域内容</div> </Card> </div> ); } 具名插槽 继续以上面的Card组件为例,假如我们现在需求发生了变化,组件的title也可以使用插槽,这时候对于Vue就可以使用具名插槽了,而React也是有办法实现的哦。 Vue实现 Vue的具名插槽主要解决的是一个组件需要多个插槽的场景,其实现是为<slot>添加name属性来实现了。 我们就上面的需求对card组件进行修改 <template> <div class="card"> <div class="card__title"> <!--如果传入了title,则使用title属性,否则使用具名插槽--> <span v-if="title">{{ title }}</span> <slot v-else name="title"></slot> </div> <div class="card__body"> <!--对于内容区域依然使用默认插槽--> <slot></slot> </div> </div> </template> <script> export default { props: { title: { type: String, default: '' } } } </script> card组件修改完之后,我们再去调整一下使用card组件的地方 <template> <div> <my-card> <!--通过v-slot:title 使用具名插槽--> <template v-slot:title> <span>这里是标题</span> </template> <div>我将被放在card组件的默认插槽里面</div> </my-card> </div> </template> <script> import MyCard from '../components/card' export default { components: { MyCard } } </script> React实现 React连插槽都没有, 更别提具名插槽了,但是没有不代表不能模拟出来。对于React的props,我们不仅仅可以传入普通的属性,还可以传入一个函数,这时候我们就可以在传入的这个函数里面返回JSX,从而就实现了具名插槽的功能。 对原有的Card组件进行修改 import React from 'react' export interface CardProps { title?: string, // 加入了一个renderTitle属性,属性类型是Function renderTitle?: Function, children: React.ReactNode } export default function(props: CardProps) { const {title, renderTitle} = props // 如果指定了renderTtile,则使用renderTitle,否则使用默认的title let titleEl = renderTitle ? renderTitle() : <span>{title}</span> return ( <div className="card"> <div className="card__title">{titleEl}</div> <div className="card__body"> {/**每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容 */} {props.children} </div> </div> ); } 这时候就可以在外部自定义title了 import React from 'react' import Card from './components/Card' export default function () { return ( <div> <Card renderTitle={ () => { return <span>我是自定义的标题</span> } }> <div>我将被放在card组件的body区域内容</div> </Card> </div> ); } 作用域插槽 有时让插槽内容能够访问子组件中才有的数据是很有用的,这个就是Vue提供作用域插槽的原因。我们继续使用上面的Card组件为例,现在我基于上面的卡片组件开发了一个人员信息卡片组件,用户直接使用人员信息卡片组件就可以将人员信息显示到界面中,但是在某些业务模块需要自定义人员信息显示方式,这时候我们就需要使用到作用域插槽了。 Vue实现 实现用户信息卡片组件,里面使用了作用域插槽 <template> <custom-card title="人员信息卡片"> <div class="content"> <!--这里使用了作用域插槽,将userInfo传出去了--> <slot name="userInfo" :userInfo="userInfo"> <!--如果没有使用插槽,则显示默认内容--> <span>姓名: {{ userInfo.name }}</span> <span>性别: {{ userInfo.sex }}</span> <span>年龄: {{ userInfo.age }}</span> </slot> </div> </custom-card> </template> <script> import CustomCard from '../card' export default { components: { CustomCard }, data() { return { userInfo: { name: '张三', sex: '男', age: 25 } } } } </script> 在外部使用人员信息组件 <template> <div> <user-card> <template v-slot:userInfo="{ userInfo }"> <div class="custom-user"> <ul> <li>姓名: {{ userInfo.name }}</li> <li>年龄: {{ userInfo.age }}</li> </ul> </div> </template> </user-card> </div> </template> <script> import UserCard from '../components/user-card' export default { components: { UserCard } } </script> React实现 在具名插槽那一小节我们通过给组件传入了一个函数,然后在函数中返回JSX的方式来模拟了具名插槽,那么对于作用域插槽,我们依然可以使用函数的这种方式,而作用域插槽传递的参数我们可以使用给函数传参的方式来替代 实现人员信息卡片组件 import React, { useState } from 'react' import Card from './Card' interface UserCardProps { renderUserInfo?: Function } export interface UserInfo { name: string; age: number; sex: string; } export default function(props: UserCardProps) { const [userInfo] = useState<UserInfo>({ name: "张三", age: 25, sex: "男", }); const content = props.renderUserInfo ? ( props.renderUserInfo(userInfo) ) : ( <div> <span>姓名: {userInfo.name}</span> <span>年龄: {userInfo.age}</span> <span>性别: {userInfo.sex}</span> </div> ); return <Card title="人员信息"> {content} </Card> } 在外部使用人员信息卡片组件 import React from 'react' import UserCard, { UserInfo } from "./components/UserCard"; export default function () { return ( <div> <UserCard renderUserInfo={(userInfo: UserInfo) => { return ( <ul> <li>姓名: {userInfo.name}</li> </ul> ); }} ></UserCard> </div> ); } Context, React中的provide/inject 通常我们在项目开发中,对于多组件之间的状态管理,在Vue中会使用到Vuex,在React中会使用到redux或者Mobx,但对于小项目来说,使用这些状态管理库就显得比较大材小用了,那么在不使用这些库的情况下,如何去完成数据管理呢?比如面试最常问的祖孙组件通信。在Vue中我们可以使用provide/inject,在React中我们可以使用Context。 假设有这样一个场景,系统现在需要提供一个换肤功能,用户可以切换皮肤,现在我们分别使用Vue和React来实现这个功能。 Vue中的provide/inject 在Vue中我们可以使用provide/inject来实现跨多级组件进行传值,就以上面所说场景为例,我们使用provide/inject来实现以下 首先,修改App.vue内容为以下内容 <template> <div id="app"> <router-view /> </div> </template> <script> export default { data() { return { themeInfo: { theme: 'dark' } } }, provide() { return { theme: this.themeInfo } } } </script> 然后在任意层级的子组件中像下面这样使用 <template> <div :class="`child-${theme.theme}`"> </div> </template> <script> export default { inject: ['theme'] } </script> 这样就可以实现theme在所有子组件中进行共享了 React中的Context 在Vue中我们使用provide/inject实现了组件跨层级传值功能,在React中也提供了类似的功能即Context,下面我们使用Context来实现相同的功能。 在项目src目录下新建context目录,添加MyContext.js文件,然后添加以下内容 import {createContext} from 'react' // 定义 MyContext,指定默认的主题为`light` export const MyContext = createContext({ theme: 'light' }) MyContext提供了一个Provider,通过Provider可以将theme共享到所有的子组件。现在我们在所有的组件的共同父组件比如App.js上面添加MyContext.Provider将theme共享出去 import { MyContext } from '@/context/MyContext'; export default function() { const [theme, setTheme] = useState('dark') return ( <MyContext.Provider value={{ theme }} > <Children></Children> </MyContext.Provider> ) } 然后这时候就可以直接在所有的子组件里面使用定义的主题theme了 import React, { useContext } from 'react' import { MyContext } from '@/context/MyContext'; export default function() { const {theme} = useContext(MyContext) return <div className={`child-${theme}`}> } 没有了v-model,但也不影响使用 我们知道React和Vue都是单向数据流的,即数据的流向都是由外层向内层组件进行传递和更新的,比如下面这段React代码就是标准的单向数据流. import React, { useState } from "react"; export default function(){ const [name] = useState('子君') return <input value={name}></input> } 在vue中使用v-model 如上代码,我们在通过通过value属性将外部的值传递给了input组件,这个就是一个简单的单向数据流。但是在使用Vue的时候,还有两个比较特殊的语法糖v-model和.sync,这两个语法糖可以让Vue组件拥有双向数据绑定的能力,比如下面的代码 <template> <input v-model="name"/> </template> <script> export default { data() { return { name:'子君' } } } </script> 通过v-model,当用户修改input的值的时候,外部的name的值也将同步被修改。但这是Vue的语法糖啊,React是不支持的,所以React应该怎么办呢?这时候再想想自定义v-model,v-model实际上是通过定义value属性同时监听input事件来实现的,比如这样: <template> <div class="custom-input"> <input :value="value" @input="$_handleChange"/> </div> </template> <script> export default { props:{ value:{ type: String, default: '' } }, methods:{ $_handleChange(e) { this.$emit('input', e.target.value) } } } </script> 在react寻找v-model替代方案 同理,React虽然没有v-model语法糖,但是也可以通过传入属性然后监听事件来实现数据的双向绑定。 import React, { useState } from 'react' export default function() { const [name, setName] = useState('子君') const handleChange = (e) => { setName(e.target.value) } return <div> <input value={name} onChange={handleChange}></input> </div> } 小编刚开始使用react,感觉没有v-model就显得比较麻烦,不过麻烦归麻烦,代码改写也要写。就像上文代码一样,每一个表单元素都需要监听onChange事件,越发显得麻烦了,这时候就可以考虑将多个onChange事件合并成一个,比如像下面代码这样 import React, { useState } from 'react' export default function () { const [name, setName] = useState('子君') const [sex, setSex] = useState('男') const handleChange = (e:any, method: Function) => { method(e.target.value) } return <div> <input value={name} onChange={(e) => handleChange(e, setName)}></input> <input value={sex} onChange={(e) => handleChange(e, setSex)}></input> </div> } 没有了指令,我感觉好迷茫 在Vue中我们一般绘制页面都会使用到template,template里面提供了大量的指令帮助我们完成业务开发,但是在React中使用的是JSX,并没有指令,那么我们应该怎么做呢?下面我们就将Vue中最常用的一些指令转换为JSX里面的语法(注意: 在Vue中也可以使用JSX) v-show与v-if 在Vue中我们隐藏显示元素可以使用v-show或者v-if,当然这两者的使用场景是有所不同的,v-show是通过设置元素的display样式来显示隐藏元素的,而v-if隐藏元素是直接将元素从dom中移除掉。 看一下Vue中的v-show与v-if的用法 <template> <div> <span v-show="showName">姓名:{{ name }}</span> <span v-if="showDept">{{ dept }}</span> </div> </template> <script> export default { data() { return { name: '子君', dept: '银河帝国', showName: false, showDept: true } } } </script> 将v-show,v-if转换为JSX中的语法 在Vue中指令是为了在template方便动态操作数据而存在的,但是到了React中我们写的是JSX,可以直接使用JS,所以指令是不需要存在的,那么上面的v-show,v-if如何在JSX中替代呢 import React, { useState } from 'react' export default function() { const [showName] = useState(false) const [showDept] = useState(true) const [userInfo] = useState({ name:'子君', dept: '银河帝国' }) return ( <div> {/**模拟 v-show */} <span style={{display: showName ? 'block' : 'none'}}>{userInfo.name}</span> {/**模拟 v-if */} {showDept ? <span>{userInfo.dept}</span>: undefined} </div> ) } v-for v-for在Vue中是用来遍历数据的,同时我们在使用v-for的时候需要给元素指定key,key的值一般是数据的id或者其他唯一且固定的值。不仅在Vue中,在React中也是存在key的,两者的key存在的意义基本一致,都是为了优化虚拟DOM diff算法而存在的。 在Vue中使用v-for <template> <div> <ul> <li v-for="item in list" :key="item.id"> {{ item.name }} </li> </ul> </div> </template> <script> export default { data() { return { list: [ { id: 1, name: '子君' }, { id: '2', name: '张三' }, { id: '3', name: '李四' } ] } } } </script> 在React中使用v-for的替代语法 在react中虽然没有v-for,但是JSX中可以直接使用JS,所以我们可以直接遍历数组 import React from 'react' export default function() { const data = [ { id: 1, name: "子君", }, { id: "2", name: "张三", }, { id: "3", name: "李四", }, ]; return ( <div> <ul> { data.map(item => { return <li key={item.id}>{item.name}</li> }) } </ul> </div> ) } v-bind与v-on v-bind在Vue中是动态绑定属性的,v-on是用于监听事件的,因为React也有属性和事件的概念,所以我们在React也能发现可替代的方式。 在Vue中使用v-bind与v-on <template> <div> <!--:value是v-bind:value的简写, @input是v-on:input的简写--> <input :value="value" @input="handleInput" /> </div> </template> <script> export default { data() { return { value: '子君' } }, methods: { handleInput(e) { this.value = e.target.value } } } </script> 在React中寻找替代方案 在Vue中,作者将事件和属性进行了分离,但是在React中,其实事件也是属性,所以在本小节我们不仅看一下如何使用属性和事件,再了解一下如何在React中自定义事件 开发一个CustomInput组件 import React from 'react' export interface CustomInputProps { value: string; //可以看出 onChange是一个普通的函数,也被定义到了组件的props里面了 onChange: ((value: string,event: React.ChangeEvent<HTMLInputElement>) => void) | undefined; } export default function(props: CustomInputProps) { function handleChange(e: React.ChangeEvent<HTMLInputElement>) { // props.onChange是一个属性,也是自定义的一个事件 props.onChange && props.onChange(e.target.value, e) } return ( <input value={props.value} onChange={handleChange}></input> ) } 使用CustomInput组件 import React, { useState } from 'react' import CustomInput from './components/CustomInput' export default function() { const [value, setValue] = useState('') function handleChange(value: string) { setValue(value) } return ( <div> <CustomInput value={value} onChange={handleChange}></CustomInput> </div> ) } 总结 刚开始从Vue转到React的时候,其实是有点不适应的,但是当慢慢的习惯之后,就会发现Vue和React是存在很多共性的,可以参考的去学习。当然无论Vue还是React,上手比较快,但是想深入学习还是需要下功夫的,后续小编将会对Vue和React的用法在做更深入的介绍,敬请期待。 最后 说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。 我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。 我可以将最近整理的前端面试题免费分享出来,其中包含HTML、CSS、JavaScript、服务端与网络、Vue、浏览器、数据结构与算法等等,还在持续整理更新中,希望大家都能找到心仪的工作。 有需要的朋友点击这里免费领取题目+解析PDF。 点击这里免费领取题目+解析PDF。

优秀的个人博客,低调大师

Volatile | 天亦凉,地亦凉,苍鹰不敢望北荒

1、相关了解 1.1.现代计算机的内存模型 其实早期计算机中cpu和内存的速度是差不多的,但在现代计算机中,cpu的指令速度远超内存的存取速度,由于计算机的储存设备与处理器的运算速度有几个数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的 高速缓存(Cach) 来作为内存与处理器之间的缓冲。 将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了。 基于高速缓存的存储交互很好地解决了处理器与内存的速度矛盾,但是也为计算机系统带来更高的复杂度,因为它引入一个新的问题:缓存一致性(CacheCoherence)。 在多处理器系统中,每个处理器都有自己的高速缓存,而它们又共享同一主内存(MainMemory)。 1.2.JMM(JavaMemoryModel) JMM:Java 内存模型,是java虚拟机规范中所定义的一种内存模型,Java 内存模型是标准化的,屏蔽掉了底层不同计算机的区别。描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量,储存到内存和从内存中读取变量这样的底层细节。 1.2.1JMM有以下规定 所有的共享变量都储存于主内存,这里所说的变量指的是实例变量和类变量,不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。 每一个线程还存在自己的工作内存,线程的工作内容,保留了被线程使用的变量的工作副本。 线程对变量的所有操作(读、取)都必须在工作内存中完成,而不能直接读写主内存中的变量。 不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存中转来完成。 本地内存和主内存的关系: 正是因为这样的机制,才导致了可见性问题的存在。 2、可见性的解决方案 加锁 /** * @Author 庭前云落 * @Date 2020/10/1 10:43 * @Description */ public class Test { public static void main(String[] args) { Tqyl a = new Tqyl(); a.start(); for (; ; ) { synchronized (a) { if (a.isFlag()) { System.out.println("庭前云落"); } } } } } 2.1.为什么加锁可以解决可见性问题呢? 因为某一个线程进入synchronized代码块前后,线程会获得锁,清空工作内存,从主内存拷贝共享变量最新的值到工作内存成为副本,执行代码,将修改后的副本的值刷新回主内存中,线程释放锁。 而获取不到锁的线程会阻塞等待,所以变量的值肯定一直都是最新的。 2.2.Volatile修饰共享变量 /** * @Author 庭前云落 * @Date 2020/10/1 10:44 * @Description */ public class Tqyl extends Thread { private volatile boolean flag = false; public boolean isFlag() { return flag; } @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } flag=true; System.out.println("flag="+flag); } } 2.3.Volatile做了什么? 每个线程操作数据的时候会把数据从主内存读取到自己的工作内存,如果它操作了数据并且写回了,其它已经读取的线程的变量副本就会失效了,需要读数据进操作又要再次去主内存中读取了。 volatile保证不同线程对共享变量操作的可见性,也就是说一个线程修改了volatile修饰的变量,当修改写回主内存时,另外一个线程立即看到最新的值。 之前我们说过当多个处理器的运算任务都涉及同一块主内存区域时,将可能导致各自的缓存数据不一致,举例说明变量在多个CPU之间的共享。 如果真的发生这种情况,那同步回到主内存时以谁的缓存数据为准呢? 为了解决一致性的问题,需要各个处理器访问缓存时都遵循一些协议,在读写时要根据协议来进行操作,这类协议有 MSI、MESI(IllinoisProtocol)、MOSI、Synapse、Firefly及DragonProtocol等。 3、MESI(缓存一致性协议) 当CPU写数据时,如果发现操作的变量是共享变量,即在其它CPU中野存在该变量的副本,会发出信息通知其它CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。 3.1.至于怎么发现数据是否失效呢? 嗅探(窃听网络上流经的数据包) 每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。 4、总线风暴 由于Volatile的MESI缓存一致性协议,需要不断的从主内存嗅探和cas不断循环,无效交互会导致总线带宽达到峰值。 所以不要大量使用Volatile,至于什么时候去使用Volatile什么时候使用锁,根据场景区分。 CAS(Compare-and-Swap):即比较并替换,是一种实现并发算法时常用到的技术,Java并发包中的很多类都使用了CAS技术。 5、禁止指令重排序 5.1.什么是重排序? 为了提高性能,编译器和处理器常常会对既定的代码执行顺序进行指令重排序。 5.2.重排序的类型有哪些呢?源码到最终执行会经过哪些重排序呢? 一个好的内存模型实际上会放松对处理器和编译器规则的束缚,也就是说软件技术和硬件技术都为同一个目标,而进行奋斗:在不改变程序执行结果的前提下,尽可能提高执行效率。 JMM对底层尽量减少约束,使其能够发挥自身优势。 因此,在执行程序时,为了提高性能,编译器和处理器常常会对指令进行重排序。 一般重排序可以分为如下三种: 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序; 指令级并行的重排序。现代化处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序; 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和储存操作看上去可能是在乱序执行的。 这里还得提一个概念,as-if-serial。 5.3.as-if-serial 不管怎么重排序,单线程下的执行结果不能被改变。 编译器、runtime和处理器都必须遵守as-if-serial语义。 那Volatile是怎么保证不会被执行重排序的呢? 5.4.内存屏障 java编译器会在生成指令系列时在适当的位置会插入 内存屏障 指令来禁止特定类型的处理器重排序。 为了实现volatile的内存语义,JMM会限制特定类型的编译器和处理器重排序,JMM会针对编译器制定volatile重排序规则表: 需要注意的是:volatile写是在前⾯和后⾯分别插⼊内存屏障,⽽volatile读操作是在后面插⼊两个内存屏障。 写 读 上面的我提过重排序原则,为了提高处理速度,JVM会对代码进行编译优化,也就是指令重排序优化,并发编程下指令重排序会带来一些安全隐患:如指令重排序导致的多个线程操作之间的不可见性。 如果让程序员再去了解这些底层的实现以及具体规则,那么程序员的负担就太重了,严重影响了并发编 程的效率。 从JDK5开始,提出了 happens-before 的概念,通过这个概念来阐述操作之间的内存可⻅性。 5.5.happens-before 如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在 happens-before关系。 volatile域规则:对一个 volatile 域的写操作,happens-before 于任意线程后续对这个volatile域的读。 如果现在我的flag变成了false,那么后面的那个操作,一定要知道我变了。 我们要知道Volatile是没办法保证原子性的,一定要保证原子性,可以使用其他方法。 无法保证原子性 就是一次操作,要么完全成功,要么完全失败。 假设现在有 N 个线程对同一个变量进行累加也是没办法保证结果是对的,因为读写这个过程并不是原子性的。 要解决也简单,要么用原子类,比如 AtomicInteger,要么加锁(记得关注Atomic的底层) 应用 /** * @Author 庭前云落 * @Date 2020/10/1 11:53 * @Description */ public class Singleton { //可见性和指令重排序都保证 private volatile static Singleton instance = null; //私有构造 public Singleton() { } public static Singleton getInstance(){ //第一重检查锁定 if(instance==null){ //同步锁定代码块 synchronized (Singleton.class){ //第二重检查锁定 if(instance==null){ //注意:非原子操作 instance = new Singleton(); } } } return instance; } } 为什么要双重检查?如果不用Volatile会怎么样? 禁止指令重排序的好处。 对象实际上创建对象要经过如下几个步骤: 分配内存空间 调用构造器,初始化实例 返回地址给引用 是可能发生指令重排序的,那有可能构造函数在对象初始化完成前就赋值完成了,在内存里面开辟一片储存区域后直接返回内存的引用,这个时候还没真正的初始化完对象。 但是别的线程去判断 instance!=null,直接拿去用了,其实这个对象是个半成品,那就有空指针异常了。 可见性怎么保证的? 因为可见性,线程A在自己的内存初始化了对象,还没来得及写回主内存,B线程也这么做了,那就创建了多个对象,不是真正意义上单例了。 6、Volatile与Synchronized的区别 volatile只能修饰实例变量和类变量,而synchronized可以修饰方法,以及代码块。 volatile保证数据的可见性,但是不保证原子性(多线程进行写操作,不保证线程安全);而synchronized是一种排他(互斥)的机制。volatile用于禁止指令重排序:可以解决单例双重检查对象初始化代码执行乱序问题。 volatile 可以看做轻量版的synchronized,volatile不保证原子性,但是如果是对一个共享变量进行多个线程的赋值,而没有其它的操作,那么就可以用 volatile 来代替 synchronized,因为赋值本身就是有原子性的,而 volatile 又保证了可见性,所以就可以保证线程安全了。 7、总结 volatile修饰符适用于以下的场景: 某个属性被多个线程共享,其中有一个线程修改了此属性,其它线程可以立即得到修改后的值,比如 booleanflag;或者作为触发器,实现轻量级同步。 volatile属性的读写操作都是无锁的,它不能替代synchronized,因为它没有提供原子性和互斥性。因为无锁,不需要花费时间在获取锁和释放锁上,所以说它是低成本的。 volatile只能作用于属性,我们用volatile修饰属性,这样compilers就不会对这个属性做指令重排序。 volatile提供了可见性,任何一个线程对其的修改将立马对其它线程可见,volatile属性不会被线程缓存,始终从主存中读取。 volatile提供了happens-before保证,对volatile变量v的写入happens-before所有其他线程后续对v的读写操作。 volatile可以使得long和double的赋值是原子的。 volatile可以在单例双重检查中实现可见性和禁止指令重排序,从而保证安全性。

优秀的个人博客,低调大师

挪森留学只用3天自助轻松搭建完美官网

网站名称:挪森留学官网公司行业:赴日留学公司规模:10-50人建站目的:建设留学网站及业务推广网站地址:www.xgdlx.com预览地址:c1553214164.qrx.hzx.imzhanlang.com建站产品:站狼美站--阿里云云市场建站产品 企业介绍: 在2008年,来自日本几位在留学生出于对春上村树《挪威的森林》的喜爱创办了挪森文学社,在当时大学里引起很多人的关注。同时,希望赴日留学的诉求也越来越多。那时也正式启动了一个目的:链接中国与日本的渠道,为帮助更多的人实现日本留学。 客户痛点: 客户想要一个方便后期管理,最好不需要什么自己技术层面过多要求的,并且可以从0到1都可以自己方便独立完成的智能建站产品。 面临挑战: 客户完全是小白,但是经过简单在线旺旺指导,其学习相关的能力很强,几乎都是完全独立完成自己的留学官网,这样漂亮的官网

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册