首页 文章 精选 留言 我的

精选列表

搜索[高并发],共10000篇文章
优秀的个人博客,低调大师

KubeSphere v4 开源并发布全新可插拔架构 LuBan

2024 年 10 月 10 日,KubeSphere 开源社区激动地向大家宣布,KubeSphere v4(开源版)已正式发布,同时发布全新可插拔架构 KubeSphere LuBan。 相较于 KubeSphere 之前所有的版本,KubeSphere v4 可以说是有了颠覆性的变化。KubeSphere v4 是基于全新的云原生可扩展开放架构------KubeSphere LuBan 打造的云原生操作系统,对于 KubeSphere 而言具有非凡的意义。 KubeSphere LuBan 什么是 KubeSphere LuBan 鲁班(LuBan),是中国古代工匠的始祖。作为广大劳动人民智慧与创造力的象征,他通过工具提高劳动效率,将劳动者从原始繁重的任务中解放出来,使土木工艺呈现崭新面貌。KubeSphere 将全新微内核架构(KubeSphere Core)命名为 LuBan,借此寓意,期待为企业与开发者提供低成本、快速迭代和灵活集成的云原生产品,并带来专业、全能和极富创造力的使用与开发体验。 KubeSphere LuBan,是一个分布式的云原生可扩展开放架构,为扩展组件提供一个可热插拔的微内核。自此,KubeSphere 所有功能组件及第三方组件都会基于 KubeSphere LuBan,以扩展组件的方式无缝融入到 KubeSphere 控制台中,并独立维护版本,真正实现即插即用的应用级云原生操作系统。 KubeSphere LuBan 架构设计如下图所示。 为什么推出 KubeSphere LuBan 自 2018 年以来,KubeSphere 混合多云容器管理平台已发布过十几个版本,其中包括三个重大版本。为了满足用户需求,KubeSphere 集成了众多企业级功能,如多租户管理,多集群管理,DevOps,GitOps,服务网格,微服务,可观测(包括监控、告警、日志、审计、事件、通知等),应用商店,边缘计算,网络与存储管理等。 虽然 KubeSphere 的一站式容器解决方案极大地提升了用户的容器使用体验,但也带来了如下挑战: 发版周期长:在发布新版本时,需要等待所有组件完成开发、测试并通过集成测试。 响应用户不及时:由于各组件无法单独迭代,KubeSphere 发布后,对社区和用户组件反馈处理需要等待 KubeSphere 发布新版本后才能一并交付给用户,导致响应不够及时。 代码耦合:尽管目前已能实现单独启用/禁用特定组件,但这些组件的前后端代码仍然耦合在一起,容易互相影响,架构上不够优雅。 系统资源占用过多:部分组件默认启用,对于没有相关需求的用户来说,可能会占用过多的系统资源。 KubeSphere LuBan 的优势有哪些 插件式的核心框架:支持独立开发和部署组件以扩展系统的功能。组件可以根据需求进行添加、升级或移除,而不需要修改核心框架的代码。 全开放的基础 UI 组件库:组件对所有人开放,任何人都可以自由地访问、使用和扩展这些组件。用户根据自己的需求进行定制和扩展,以满足不同的设计和功能要求。 前后端热更新、热修复:开发者可以在系统运行时对前端和后端进行实时更新和修复,提高了开发和运维的效率,同时保证了应用程序的可用性和用户体验。 开放性扩展中心,生态共建:我们提供一个开放的平台,鼓励第三方开发者通过组件向系统添加新的功能或增强现有功能,在系统的框架内进行开发和集成,并将他们的组件与系统进行无缝连接,共同构建一个健康、繁荣的生态系统。 基于 KubeSphere LuBan 可以做什么 KubeSphere 用户 KubeSphere 用户可以自由选择启用哪些 KubeSphere 扩展组件。同时还能将自己的应用无缝融入到 KubeSphere 控制台。此外,随着 KubeSphere 扩展组件生态的丰富,用户可以在 KubeSphere 扩展市场中自由选择更丰富的产品和服务,最终实现容器管理平台的千人千面的效果。 KubeSphere 维护者 扩展机制使得维护者可以更聚焦 KubeSphere 核心功能的开发,并可使得 KubeSphere Core 更加轻量,版本发布节奏也可以加快。此外,因为扩展组件能够独立进行迭代,能够更及时地满足用户的需求。 KubeSphere 贡献者 扩展机制的引入使得 KubeSphere Core 及 KubeSphere 其他扩展组件变得更加松耦合,开发也更加易于上手。 云原生应用开发商(ISV)或其他开源项目 众多 ISV 或其他开源项目可以低成本将产品或开源项目无缝融入到 KubeSphere 生态系统中。比如 Karmada/KubeEdge 的开发人员可以基于 KubeSphere LuBan 开发独立的 Karmada/KubeEdge 控制台。 KubeSphere v4 简介 KubeSphere v4,是 KubeSphere 团队打造的全新云原生操作系统,不仅继承了之前版本的企业级资源与业务管理、一站式云原生解决方案等强大功能,还能轻松实现应用的上下游联动、随时随地集成各类优质扩展组件,并提供无缝融合的业务能力与高度一致的产品体验。 其中内核部分(KubeSphere Core)仅包含系统运行的必备基础功能,而将独立的业务模块分别封装在各个扩展组件(Extensions)中。 新特性 基于全新微内核架构 KubeSphere LuBan 重构 内置 KubeSphere 扩展市场 支持通过扩展中心统一管理扩展组件 支持 UI、API 扩展 支持通过 kubeconfig 一键导入 member 集群 支持 KubeSphere 服务帐户 支持动态扩展 Resource API 支持添加集群、企业空间、项目到快捷访问 支持通过容器终端进行文件上传和下载 支持适配不同厂商的云原生网关(Kubernetes Ingress API) 支持 API 限流 支持在页面创建持久卷 支持基于 OCI 的 Helm Chart 仓库 另外,KubeSphere 4.1.2 增加了默认的扩展组件仓库(见下文)。 同时修复了 KubeSphere 4.1.1 存在的以下问题: 部分扩展组件页面白屏的问题 ks-core 卸载时部分资源残留的问题 K8s 1.19 环境无法安装的问题 其他变化请查看变更说明: https://www.kubesphere.io/zh/docs/v4.1/20-release-notes/release-v411/ https://www.kubesphere.io/zh/docs/v4.1/20-release-notes/release-v412/ KubeSphere 扩展组件 KubeSphere 扩展组件用于扩展 KubeSphere 的平台能力,用户可在系统运行时动态地安装、卸载、启用、禁用扩展组件。 监控、告警、通知、项目网关和集群网关、卷快照、网络隔离等功能,将由扩展组件来提供。 目前,我们已经开源了 20 个扩展组件,分别是: KubeSphere 网络 KubeSphere 应用商店管理 KubeSphere 服务网格 KubeSphere 存储 KubeSphere 多集群代理连接 KubeSphere 网关 DevOps 联邦集群应用管理 OpenSearch 分布式检索与分析引擎 Grafana for WhizardTelemetry Grafana Loki for WhizardTelemetry WhizardTelemetry 数据流水线 WhizardTelemetry 平台服务 WhizardTelemetry 告警 WhizardTelemetry 事件 WhizardTelemetry 日志 WhizardTelemetry 监控 WhizardTelemetry 通知 Metrics Server Gatekeeper 扩展组件仓库:https://github.com/kubesphere-extensions/ks-extensions/。 安装试用 特别说明:目前不支持从 3.4.x 版本直接升级到 v4 版本,需要先卸载原来的版本,再安装 v4 版本。 参考文档:https://www.kubesphere.io/zh/docs/v4.1/03-installation-and-upgrade/02-install-kubesphere/02-install-kubernetes-and-kubesphere/ 安装扩展组件参考文档:https://www.kubesphere.io/zh/docs/v4.1/06-extension-user-guide/01-install-components-pdf/ 从 v4.1.1 升级到 v4.1.2,升级和安装部署可以使用以下命令: helm upgrade --install -n kubesphere-system --create-namespace ks-core https://charts.kubesphere.io/main/ks-core-1.1.2.tgz --debug --wait 详细文档请参考:https://kubesphere.io/zh/docs/v4.1/02-quickstart/01-install-kubesphere。 参与贡献 正如前文所说,扩展机制的引入使得 KubeSphere Core 及 KubeSphere 其他扩展组件变得更加松耦合,开发也更加易于上手。 社区目前正在逐步发布开源的扩展组件,为各位用户提供更多的功能,让各位用户有更多的选择。同时,社区也非常欢迎各位开发者以及 ISV 参与进来,开发自己的扩展组件,共同丰富扩展组件生态。 目前,已经有一位参与开源之夏的学生贡献者张豈明,开发了一款扩展组件 Pod Status Analysis Tool,地址:https://github.com/kubesphere-extensions/ks-extensions-contrib/tree/main/pod-analyzer。 贡献仓库:https://github.com/kubesphere-extensions/ks-extensions-contrib 开发指南:https://dev-guide.kubesphere.io/extension-dev-guide/zh/ 未来计划与展望 KubeSphere 愿景是打造一个以 Kubernetes 为内核的云原生分布式操作系统,它的架构可以非常方便地使第三方应用与云原生生态组件进行即插即用(plug-and-play)的集成,支持云原生应用在多云与多集群的统一分发和运维管理。 KubeSphere v4 将正式实现这个愿景,真正成为可插拔架构的产品,让用户可以选择自己需要的组件。 后续,我们将开源更多的扩展组件,为用户提供更多的选择。 后续文章将为大家详细讲解如何安装部署 KubeSphere v4,如何安装和使用扩展组件以及目前大家在使用中遇到的常见问题解答,敬请关注。 本文由博客一文多发平台 OpenWrite 发布!

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

X File Storage 捐赠至 Dromara 开源组织并发布 2.0.0 版本

原名 X Spring File Storage 现已捐赠至 dromara 开源组织 x-file-storage.dromara.org | x-file-storage.xuyanwu.cn | spring-file-storage.xuyanwu.cn 📚简介 一行代码将文件存储到本地、FTP、SFTP、WebDAV、阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS、百度云 BOS、又拍云 USS、MinIO、 Amazon S3、GoogleCloud Storage、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 网易数帆 NOS、Ucloud US3、青云 QingStor、平安云 OBS、首云 OSS、IBM COS、其它兼容 S3 协议的存储平台。查看 所有支持的存储平台 💡 通过 WebDAV 连接到 Alist 后,可以使用百度网盘、天翼云盘、阿里云盘、迅雷网盘等常见存储服务,查看 Alist 支持的存储平台 GitHub:github.com/dromara/x-f… Gitee:gitee.com/dromara/x-f… 文档1:x-file-storage.dromara.org 文档2:x-file-storage.xuyanwu.cn 文档3:spring-file-storage.xuyanwu.cn 📜更新内容 更改项目名、更改包名、优化项目结构 新增直接读取 HttpServletRequest 的流进行上传,文件不落盘,速度更快 新增支持 Metadata 元数据 优化 ACL 异常处理 优化文件删除逻辑 修复 Amazon S3 上传文件偶现 ResetException 问题 捐赠至 dromara 开源社区 项目依赖的变化 2.0.0 之前的版本 <dependency> <groupId>cn.xuyanwu</groupId> <artifactId>spring-file-storage</artifactId> <version>1.0.3</version> </dependency> 2.0.0 及以后的版本 <dependency> <groupId>org.dromara.x-file-storage</groupId> <artifactId>x-file-storage-spring</artifactId> <version>2.0.0</version> </dependency> 配置参数的变化 2.0.0 之前的版本 spring: file-storage: #文件存储配置 default-platform: huawei-obs-1 #默认使用的存储平台 thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】 #对应平台的配置写在这里,注意缩进要对齐 2.0.0 及以后的版本 dromara: x-file-storage: #文件存储配置 default-platform: huawei-obs-1 #默认使用的存储平台 thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】 #对应平台的配置写在这里,注意缩进要对齐 包名的变化 2.0.0 之前的版本 cn.xuyanwu.spring.file.storage cn.xuyanwu.spring.file.storage.spring 2.0.0 及以后的版本 org.dromara.x.file.storage.core org.dromara.x.file.storage.spring 📦使用 点击 快速入门 查看全部存储平台的使用方法! 🔧 配置 这里以阿里云 OSS 为例,pom.xml 引入本项目,这里默认是 SpringBoot 环境,其它环境参考 脱离 SpringBoot 单独使用 <!-- 引入本项目 --> <dependency> <groupId>org.dromara.x-file-storage</groupId> <artifactId>x-file-storage-spring</artifactId> <version>2.0.0</version> </dependency> <!-- 引入 阿里云 OSS SDK,如果使用其它存储平台,就引入对应的 SDK --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.16.1</version> </dependency> application.yml配置文件中添加以下基础配置 dromara: x-file-storage: #文件存储配置 default-platform: aliyun-oss-1 #默认使用的存储平台 aliyun-oss: - platform: aliyun-oss-1 # 存储平台标识 enable-storage: true # 启用存储 access-key: ?? secret-key: ?? end-point: ?? bucket-name: ?? domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/ base-path: test/ # 基础路径 🔨编码 在启动类上加上@EnableFileStorage注解 @EnableFileStorage @SpringBootApplication public class SpringFileStorageTestApplication { public static void main(String[] args) { SpringApplication.run(SpringFileStorageTestApplication.class,args); } } ✨开始上传 支持 File、MultipartFile、byte[]、InputStream、URL、URI、String、HttpServletRequest,大文件会自动分片上传。如果想支持更多方式,请阅读 文件适配器 章节 @RestController public class FileDetailController { @Autowired private FileStorageService fileStorageService;//注入实列 /** * 上传文件 */ @PostMapping("/upload") public FileInfo upload(MultipartFile file) { //只需要这一行代码即可上传成功 return fileStorageService.of(file).upload(); } /** * 上传文件,成功返回文件 url */ @PostMapping("/upload2") public String upload2(MultipartFile file) { FileInfo fileInfo = fileStorageService.of(file) .setPath("upload/") //保存到相对路径下,为了方便管理,不需要可以不写 .setObjectId("0") //关联对象id,为了方便管理,不需要可以不写 .setObjectType("0") //关联对象类型,为了方便管理,不需要可以不写 .putAttr("role","admin") //保存一些属性,可以在切面、保存上传记录、自定义存储平台等地方获取使用,不需要可以不写 .upload(); //将文件上传到对应地方 return fileInfo == null ? "上传失败!" : fileInfo.getUrl(); } /** * 上传图片,成功返回文件信息 * 图片处理使用的是 https://github.com/coobird/thumbnailator */ @PostMapping("/upload-image") public FileInfo uploadImage(MultipartFile file) { return fileStorageService.of(file) .image(img -> img.size(1000,1000)) //将图片大小调整到 1000*1000 .thumbnail(th -> th.size(200,200)) //再生成一张 200*200 的缩略图 .upload(); } /** * 上传文件到指定存储平台,成功返回文件信息 */ @PostMapping("/upload-platform") public FileInfo uploadPlatform(MultipartFile file) { return fileStorageService.of(file) .setPlatform("aliyun-oss-1") //使用指定的存储平台 .upload(); } /** * 直接读取 HttpServletRequest 中的文件进行上传,成功返回文件信息 * 使用这种方式有些注意事项,请查看文档 基础功能-上传 章节 */ @PostMapping("/upload-request") public FileInfo uploadPlatform(HttpServletRequest request) { return fileStorageService.of(request).upload(); } } 🎨其它操作 //手动构造文件信息,可用于其它操作 FileInfo fileInfo = new FileInfo() .setPlatform("huawei-obs-1") .setBasePath("test/") .setPath("aa/") .setFilename("image.png") .setThFilename("image.png.min.jpg"); //文件是否存在 boolean exists = fileStorageService.exists(fileInfo); //下载 byte[] bytes = fileStorageService.download(fileInfo).bytes(); //删除 fileStorageService.delete(fileInfo); //其它更多操作 如果将文件记录保存到数据库中,还可以更方便的根据 URL 进行操作了,详情请阅读保存上传记录章节 //直接从数据库中获取 FileInfo 对象,更加方便执行其它操作 FileInfo fileInfo = fileStorageService.getFileInfoByUrl("https://abc.def.com/test/aa/image.png"); //文件是否存在 boolean exists = fileStorageService.exists("https://abc.def.com/test/aa/image.png"); //下载 byte[] bytes = fileStorageService.download("https://abc.def.com/test/aa/image.png").bytes(); //删除 fileStorageService.delete("https://abc.def.com/test/aa/image.png"); //其它更多操作 点击快速入门查看全部存储平台的使用方法! 🚀Dromara成员项目 为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。

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

Java并发编程专题系列之从底层分析LockSupport原理机制

从底层分析LockSupport原理机制 知识点 LockSupport的介绍 LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语。LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,只有两个函数,而仅仅两个简单的接口,就为上层提供了强大的同步原语,先来解析下两个函数是做什么的。 public native void unpark(Thread jthread); public native void park(boolean isAbsolute, long time); park:阻塞当前线程(Block current thread),字面理解park,就算占住,停车的时候不就把这个车位给占住了么?起这个名字还是很形象的。 isAbsolute参数是指明时间是否属于绝对。 time参数是指时间值 线程调用park函数则等待"许可"。 unpark: 使给定的线程停止阻塞(Unblock the given thread blocked)。 thread参数是指对相应的线程进行解除阻塞。 线程调用unpark函数为线程提供"许可(permit)"。 这个有点像信号量,但是这个"许可"是不能叠加的,"许可"是一次性的。 比如,线程B连续调用了三次unpark函数,当线程A调用park函数就使用掉这个"许可",如果线程A再次调用park,则进入等待状态。 注意,unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个"许可",那么当线程A调用park时,它发现已经有"许可"了,那么它会马上再继续运行。(此部分比wait/notify(notifyAll))要好很多。 park和unpark的灵活之处 unpark函数可以先于park调用,这个正是它们的灵活之处。 一个线程它有可能在别的线程unPark之前,或者之后,或者同时调用了park,那么因为park的特性,它可以不用担心自己的park的时序问题,否则,如果park必须要在unpark之前。 考虑一下,两个线程同步,要如何处理? 在Java5里是用wait/notify/notifyAll来同步的。wait/notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。 另外,是调用notify,还是notifyAll? notify只会唤醒一个线程,如果错误地有两个线程在同一个对象上wait等待,那么又悲剧了。为了安全起见,貌似只能调用notifyAll了。 park/unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Object或者其它变量来存储状态,不再需要关心对方的状态。 拓展延伸 HotSpot里park/unpark的实现,每个java线程都有一个Parker实例,Parker类是这样定义的: class Parker : public os::PlatformParker { private: volatile int _counter ; ... public: void park(bool isAbsolute, jlong time); void unpark(); ... } class PlatformParker : public CHeapObj<mtInternal> { protected: pthread_mutex_t _mutex [1] ; pthread_cond_t _cond [1] ; ... } 可以看到Parker类实际上用Posix的mutex,condition来实现的。 在Parker类里的_counter字段,就是用来记录所谓的“许可”的。 当调用park时,先尝试直接能否直接拿到"许可",即_counter>0时,如果成功,则把_counter设置为0,并返回:(和信号量的思路很像!) void Parker::park(bool isAbsolute, jlong time) { // Ideally we'd do something useful while spinning, such // as calling unpackTime(). // Optional fast-path check: // Return immediately if a permit is available. // We depend on Atomic::xchg() having full barrier semantics // since we are doing a lock-free update to _counter. if (Atomic::xchg(0, &_counter) > 0) return; 如果不成功,则构造一个ThreadBlockInVM,然后检查_counter是不是>0,如果是,则把_counter设置为0,unlock mutex并返回: ThreadBlockInVM tbivm(jt); if (_counter > 0) { // no wait needed _counter = 0; status = pthread_mutex_unlock(_mutex); 否则,再判断等待的时间,然后再调用pthread_cond_wait函数等待,如果等待返回,则把_counter设置为0,unlock mutex并返回: if (time == 0) { status = pthread_cond_wait (_cond, _mutex) ; } _counter = 0 ; status = pthread_mutex_unlock(_mutex) ; assert_status(status == 0, status, "invariant") ; OrderAccess::fence(); 当unpark时,则简单多了,直接设置_counter为1,再unlock mutext返回。如果_counter之前的值是0,则还要调用pthread_cond_signal唤醒在park中等待的线程: void Parker::unpark() { int s, status ; status = pthread_mutex_lock(_mutex); assert (status == 0, "invariant") ; s = _counter; _counter = 1; if (s < 1) { if (WorkAroundNPTLTimedWaitHang) { status = pthread_cond_signal (_cond) ; assert (status == 0, "invariant") ; status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant") ; } else { status = pthread_mutex_unlock(_mutex); assert (status == 0, "invariant") ; status = pthread_cond_signal (_cond) ; assert (status == 0, "invariant") ; } } else { pthread_mutex_unlock(_mutex); assert (status == 0, "invariant") ; } } 用mutex和condition保护了一个_counter的变量,当park时,这个变量置为了0,当unpark时,这个变量置为1。 值得注意的是在park函数里,调用pthread_cond_wait时,并没有用while来判断,所以posix condition里的"Spurious wakeup"一样会传递到上层Java的代码里。 if (time == 0) { status = pthread_cond_wait (_cond, _mutex) ; } 这也就是为什么Java dos里提到,当下面三种情况下park函数会返回: Some other thread invokes unpark with the current thread as the target; or Some other thread interrupts the current thread; or The call spuriously (that is, for no reason) returns. 相关的实现代码在: http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/share/vm/runtime/park.hpp http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/share/vm/runtime/park.cpp http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/os/linux/vm/os_linux.hpp http://hg.openjdk.java.net/build-infra/jdk7/hotspot/file/52c4a1ae6adc/src/os/linux/vm/os_linux.cpp 其它的一些东东: Parker类在分配内存时,使用了一个技巧,重载了new函数来实现了cache line对齐。 // We use placement-new to force ParkEvent instances to be // aligned on 256-byte address boundaries. This ensures that the least // significant byte of a ParkEvent address is always 0. void * operator new (size_t sz) ; Parker里使用了一个无锁的队列在分配释放Parker实例: volatile int Parker::ListLock = 0 ; Parker * volatile Parker::FreeList = NULL ; Parker * Parker::Allocate (JavaThread * t) { guarantee (t != NULL, "invariant") ; Parker * p ; // Start by trying to recycle an existing but unassociated // Parker from the global free list. for (;;) { p = FreeList ; if (p == NULL) break ; // 1: Detach // Tantamount to p = Swap (&FreeList, NULL) if (Atomic::cmpxchg_ptr (NULL, &FreeList, p) != p) { continue ; } // We've detached the list. The list in-hand is now // local to this thread. This thread can operate on the // list without risk of interference from other threads. // 2: Extract -- pop the 1st element from the list. Parker * List = p->FreeNext ; if (List == NULL) break ; for (;;) { // 3: Try to reattach the residual list guarantee (List != NULL, "invariant") ; Parker * Arv = (Parker *) Atomic::cmpxchg_ptr (List, &FreeList, NULL) ; if (Arv == NULL) break ; // New nodes arrived. Try to detach the recent arrivals. if (Atomic::cmpxchg_ptr (NULL, &FreeList, Arv) != Arv) { continue ; } guarantee (Arv != NULL, "invariant") ; // 4: Merge Arv into List Parker * Tail = List ; while (Tail->FreeNext != NULL) Tail = Tail->FreeNext ; Tail->FreeNext = Arv ; } break ; } if (p != NULL) { guarantee (p->AssociatedWith == NULL, "invariant") ; } else { // Do this the hard way -- materialize a new Parker.. // In rare cases an allocating thread might detach // a long list -- installing null into FreeList --and // then stall. Another thread calling Allocate() would see // FreeList == null and then invoke the ctor. In this case we // end up with more Parkers in circulation than we need, but // the race is rare and the outcome is benign. // Ideally, the # of extant Parkers is equal to the // maximum # of threads that existed at any one time. // Because of the race mentioned above, segments of the // freelist can be transiently inaccessible. At worst // we may end up with the # of Parkers in circulation // slightly above the ideal. p = new Parker() ; } p->AssociatedWith = t ; // Associate p with t p->FreeNext = NULL ; return p ; } void Parker::Release (Parker * p) { if (p == NULL) return ; guarantee (p->AssociatedWith != NULL, "invariant") ; guarantee (p->FreeNext == NULL , "invariant") ; p->AssociatedWith = NULL ; for (;;) { // Push p onto FreeList Parker * List = FreeList ; p->FreeNext = List ; if (Atomic::cmpxchg_ptr (p, &FreeList, List) == List) break ; } }

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

Java并发编程专题系列之深入分析synchronized(基础篇)

synchronized同步关键字简介 synchronized是属于JVM层面的一个关键字,底层是通过一个monitor对象(管程对象)来完成,由于wait()/notify()等方法也依赖于monitor对象,所以只有在同步的块或者方法中才能调用wait/notify等方法 synchronized同步代码块底层实现 synchronized同步语句块的实现使用monitorenter和 monitorexit 指令。 monitorenter:指令指向同步代码块的开始位置 monitorexit:指令则指明同步代码块的结束位置 synchronized获取锁 当执行monitorenter指令时,当前线程将试图获取objectref(即对象锁) 所对应的 monitor的持有权,当 objectref的monitor 的进入计数器**为0,那线程可以成功取得 monitor,并将计数器值设置为 1,取锁成功。 如果当前线程已经拥有 objectref 的 monitor 的持有权,那它可以重入这个 monitor (关于重入性稍后会分析),重入时计数器的值也会加 1。 倘若其他线程已经拥有objectref 的 monitor 的所有权,那当前线程将被阻塞,直到正在执行线程执行完毕,即monitorexit指令被执行,执行线程将释放monitor(锁)并设置计数器值为0,其他线程将有机会持有 monitor ;** 为了保证在方法异常完成时 monitorenter 和 monitorexit 指令依然可以正确配对执行,编译器会自动产生一个异常处理器,这个异常处理器声明可处理所有的异常,它的目的就是用来执行 monitorexit 指令。 从字节码中也可以看出多了一个monitorexit指令,它就是异常结束时被执行的释放monitor的指令; monitorenter(进入管程对象) 每个对象有一个管程对象(monitor),当monitor被占用时就会处于锁定状态;线程执行monitorenter指令时尝试获取monitor的所有权,过程如下: 如果monitor的进入计数器为0,则该线程进入monitor,然后将进入计数器设置为1,该线程即为monitor的所有者; 如果线程已经之前占用了该monitor,本次只是重新进入,则将monitor的进入计数器加1; 如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入计数器为0,再重新尝试获取monitor的所有权; monitorexit(退出管程对象) 执行monitorexit的线程必须是objectref(即对象锁)所对应的monitor的所有者; 指令执行时,monitor的进入计数器减1,如果减1后进入计数器为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权. 同步方法中synchronized底层实现 方法级的同步是隐式,即无需通过字节码指令(monitorenter和monitorexit)来控制的。 它实现在方法调用和返回操作之中。 JVM可以从方法常量池中的方法表结构(method_info Structure) 中的ACC_SYNCHRONIZED访问标志区分一个方法是否同步方法。 当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有monitor(虚拟机规范中用的是管程一词)。 然后再执行方法,最后在方法完成(无论是正常完成还是非正常完成)时释放monitor。 在方法执行期间,执行线程持有了monitor,其他任何线程都无法再获得同一个monitor。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的monitor将在异常抛到同步方法之外时自动释放。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

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

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文件系统,支持十年生命周期更新。

用户登录
用户注册