Linux/AndroidOS中进程间的通信线程间的同步 - IPC方式简介
前言
- 从来没有总结过Linux/Android系统中进程间的通信方式和线程间的同步方式,这个专栏就系统总结讨论一下。
- 首先从标题可知,讨论问题的主体是进程和线程、通信和同步;在这里默认你理解进程和线程的区别。
- 通信和同步有什么概念上的区别?理论上说进程也可以通信/同步,线程也可以通信/同步,只不过现实情况进程更多的需要是通信,而线程更多的需要是同步。
- 参考了一些书籍和资料,太多就不列出来了。
1 通信/同步 工具分类
Inter-Process Communication(IPC)和Inter-Thread Synchronization(ITS)
- 通信:这些工具关注进程之间的数据交换。
- 同步:这些进程关注进程和线程操作之间的同步。
- 信号:尽管信号的主要作用并不在此,但在特定场景下仍然可以将它作为一种同步技术。更罕见的是信号还可以作为一种通信技术:信号编号本身是一种形式的信息,并且可以在实时信号上绑定数据(一个整数或指针)。

2 通信工具
上图列出的各种通信工具允许进程间相互交换数据。(这些工具还可以用来在同一个进程中不同线程之间交换数据,但很少需要这样做,因为线程之间可以通过共享全局变量来交换信息。)
可以将通信工具分成两类。
- 数据传输工具:区分这些工具的关键因素是写入和读取的概念。为了进行通信,一个进程将数据写入到 IPC 工具中,另一个进程从中读取数据。这些工具要求在用户内存和内核内存之间进行两次数据传输:一次传输是在写入的时候从用户内存到内核内存,另一次传输是在读取的时候从内核内存到用户内存。
- 共享内存:共享内存允许进程通过将数据放到由进程间共享的一块内存中以完成信息的交换。(内核通过将每个进程中的页表条目指向同一个 RAM 分页来实现这一功能,如图 49-2 所示。)一个进程可以通过将数据放到共享内存块中使得其他进程读取这些数据。由于通信无需系统调用以及用户内存和内核内存之间的数据传输,因此共享内存的速度非常快。
2.1 数据传输
可以进一步将数据传输工具分成下列类别。
-
字节流:通过管道、FIFO 以及数据报 socket 交换的数据是一个无分隔符的字节流。每个读取操作可能会从 IPC 工具中读取任意数量的字节,不管写者写入的块的大小是什么。这个模型参考了传统的 UNIX“文件是一个字节序列”模型。
-
消息:通过 System V 消息队列、POSIX 消息队列以及数据报 socket 交换的数据是以分隔符分隔的消息。每个读取操作读取由写者写入的一整条消息,无法只读取部分消息,而把剩余部分留在 IPC 工具中,也无法在一个读取操作中读取多条消息。
-
伪终端:伪终端是一种在特殊情况下使用的通信工具,在 64 章将会介绍有关伪终端的详细信息。数据传输工具和共享内存之间的差别包括以下几个方面。
-
尽管一个数据传输工具可能会有多个读取者,但读取操作是具有破坏性的。读取操作会消耗数据,其他进程将无法获取所消耗的数据。
-
读取者和写者进程之间的同步是原子的。如果一个读取者试图从一个当前不包含数据的数据传输工具中读取数据,那么在默认情况下读取操作会被阻塞直至一些进程向该工具写入了数据。
2.2 共享内存
大多数现代 UNIX 系统提供了三种形式的共享内存:System V 共享内存、POSIX 共享内存以及内存映射。在后面介绍这些工具的章节中将会描述它们之间的差别。下面是使用共享内存时的注意点。
-
尽管共享内存的通信速度更快,但速度上的优势是用来弥补需要对在共享内存上发生的操作进行同步的不足的。如当一个进程正在更新共享内存中的一个数据结构时,另一个进程就不应该试图读取这个数据结构。在共享内存中,信号量通常用来作为同步方法。
-
放入共享内存中的数据对所有共享这块内存的进程可见。(这与上面数据传输工具中介绍的破坏性读取语义不同。)
3 同步工具
通过图 1 中的同步工具可以协调进程的操作。通过同步可以防止进程执行诸如同时更新一块共享内存或同时更新文件的同一个数据块之类的操作。如果没有同步,那么这种同时更新的操作可能会导致应用程序产生错误的结果。UNIX 系统提供了下列同步工具。
-
信号量:一个信号量是一个由内核维护的整数,其值永远不会小于 0。一个进程可以增加或减小一个信号量的值。如果一个进程试图将信号量的值减小到小于 0,那么内核会阻塞该操作直至信号量的值增长到允许执行该操作的程度。(或者进程可以要求
执行一个非阻塞操作,那么就不会发生阻塞,内核会让该操作立即返回并返回一个标示无法立即执行该操作的错误。)信号量的含义是由应用程序来确定的。一个进程减小一个信号量(如从 1 到 0)是为了预约对某些共享资源的独占访问,在完成了资源
的使用之后可以增加信号量来释放共享资源以供其他进程使用。最常用的信号量是二元信号量——一个值只能是 0 或 1 的信号量,但处理一类共享资源拥有多个实例的应用程序需要使用最大值等于共享资源数量的信号量。Linux 既提供了 System V 信号量,又提供了 POSIX 信号量,它们的功能是类似的。 -
文件锁:文件锁是设计用来协调操作同一文件的多个进程的动作的一种同步方法。它也可以用来协调对其他共享资源的访问。文件锁分为两类:读(共享)锁和写(互斥)锁。任意进程都可以持有同一文件(或一个文件的某段区域)的读锁,但当一个进程
持有了一个文件(或文件区域)的写锁之后,其他进程将无法获取该文件(或文件区域)上的读锁和写锁。Linux 通过 flock()和 fcntl()系统调用来提供文件加锁工具。flock()系统调用提供了一种简单的加锁机制,允许进程将一个共享或互斥锁加到整个文件
上。由于功能有限,现在已经很少使用 flock()这个加锁工具了。fcntl()系统调用提供了记录加锁,允许进程在同一文件的不同区域上加上多个读锁和写锁。 -
互斥体和条件变量:这些同步工具通常用于 POSIX 线程。
在执行进程间同步时通常需要根据功能需求来选择工具。当协调对文件的访问时文件记录加锁通常是最佳的选择,而对于协调对其他共享资源的访问来讲,信号量通常是更佳的选择。
通信工具也可以用来进行同步。如在 44.3 节中使用了一个管道来同步父进程与子进程的动作。一般来讲,所有数据传输工具都可以用来同步,只是同步操作是通过在工具中交换消息来完成的。
4 IPC工具比较
在需要使用 IPC 时会发现有很多选择,在一开始可能会对这些选择感到迷惑。下面介绍在确定选择何种 IPC 工具时通常需要考虑的事项。
4.1 IPC 对象标识和打开对象的句柄
要访问一个 IPC 对象,进程必须要通过某种方式来标识出该对象,一旦将对象“打开”之后,进程必须要使用某种句柄来引用该打开着的对象。下表对各种类型的 IPC 工具的属性进行了总结。

4.2 功能
各种 IPC 工具在功能上是存在差异的,因此在确定使用何种工具时需要考虑这些差异。下面首先对数据传输工具盒共享内存之间的差异进行总结。
-
数据传输工具提供了读取和写入操作,传输的数据只供一个读者进程消耗。内核会自动处理读者和写者之间的流控以及同步(这样当读者试图从当前为空的工具中读取数据时将会阻塞)。在很多应用程序设计中,这个模型都表现得很好。
-
其他应用程序设计则更适合采用共享内存的方式。一个进程通过共享内存能够使数据对共享同一内存区域的所有进程可见。通信“操作”是比较简单的——进程可以像访问自己的虚拟地址空间中的内存那样访问共享内存中的数据。另一个方面,同步处理(可能还会有流控)会增加共享内存设计的复杂性。在需要维护共享状态(如共享数据结构)的应用程序中,这个模型表现得很好。
关于各种数据传输工具,下面几点是值得注意的。
-
一些数据传输工具以字节流的形式传输数据(管道、FIFO 以及流 socket),另一些则是面向消息的(消息队列和数据报 socket)。到底选择何种方法则需要依赖于应用程序。(应用程序也可以在一个字节流工具上应用面向消息的模型,这可以通过使用分隔字符、固定长度的消息,或对整条消息长度进行编码的消息头来实现)。
-
与其他数据传输工具相比,System V 和 POSIX 消息队列特有的一个特性是它们能够给消息赋一个数值类型或优先级,这样递送消息的顺序就可以与发送消息的顺序不同了。
-
管道、FIFO 以及 socket 是使用文件描述符来实现的。这些 IPC 工具都支持 I/O 多路复用(select()和 poll()系统调用)、信号驱动的 I/O、以及 Linux 特有的 epoll API。这些技术的主要优势在于它们允许应用程序同时监控多个文件描述符以判断是否可以在某些文件描述符上执行 I/O 操作。与之相比,System V 消息队列没有使用文件描述符,因此并不支持这些技术。
-
POSIX 消息队列提供了一个通知工具,当一条消息进入了一个之前为空的队列中时可以使用它来向进程发送信号或实例化一个新线程。
-
UNIX domain socket 提供了一个特性允许在进程间传递文件描述符。这样一个进程就能够打开一个文件并使之对另一个本来无法访问该文件的进程可用。
-
UDP(Internet domain datagram)socket 允许一个发送者向多个接收者广播或组播一条消息。
关于进程同步工具,下面几点是值得注意的。
-
使用 fcntl()加上的记录锁由加锁的进程拥有。内核使用这种所有权属性来检测死锁(两个或多个进程持有的锁会阻塞对方后续的加锁请求的场景)。如果发生了死锁,那么内核会拒绝其中一个进程的加锁请求,因此会在 fcntl()调用中返回一个错误标示出死锁的发生。System V 和 POSIX 信号量并没有所有权属性,因此内核不会为信号量进行死锁检测。
-
当使用 fcntl()获得记录锁的进程终止之后会自动释放该记录锁。System V 信号量提供了一个类似的特性,即“撤销”特性,但这个特性仅在部分场景中可靠。POSIX 信号量并没有提供类似的特性。
4.3 网络通信
在图 1 中给出所有 IPC 方法中,只有 socket 允许进程通过网络来通信。socket 一般用于两个域中:一个是 UNIX domain,它允许位于同一系统上的进程进行通信;另一个是 Internet domain,它允许位于通过 TCP/IP 网络进行连接的不同主机上的进程进行通信。通常,将一个使用 UNIX domain socket进行通信的程序转换成一个使用 Internet domain socket进行通信的程序只需要做出微小的改动,这样只需要对使用 UNIX domain socket 的应用程序做较小的改动就可以将它应用于网络场景。
4.4 可移植性
现代 UNIX 实现支持图 1 中的大部分 IPC 工具,但 POSIX IPC 工具(消息队列、信号量以及共享内存)的普及程度远远不如 System V IPC,特别是在较早的 UNIX 系统上。(只有版本为 2.6.x 的 Linux 内核系列才提供了一个 POSIX 消息队列的实现以及对 POSIX 信号量的完全支持。)因此,从可移植性的角度来看,System V IPC 要优于 POSIX IPC。
4.5 可访问性
下表中的第二列总结了各种 IPC 工具的一个重要特性:权限模型控制着哪些进程能够访问对象。下面介绍各种模型的细节信息。
-
对于一些 IPC 工具(如 FIFO 和 socket),对象名位于文件系统中,可访问性是根据相关的文件权限掩码(指定了所有者、组和其他用户的权限)来确定的。虽然 System V IPC 对象并不位于文件系统中,但每个对象拥有一个相关的权限掩码,其语义与文件的权限掩码类似。
-
一些 IPC 工具(管道、匿名内存映射)被标记成只允许相关进程访问。这里“相关”指通过 fork()关联的。为了使两个进程能够访问同一个对象,其中一个必须要创建该对象,然后调用 fork()。而 fork()调用的结果就是子进程会继承引用该对象的一个句柄,这样两个进程就能够共享对象了。
-
POSIX 的未命名信号量的可访问性是通过包含该信号量的共享内存区域的可访问性来确定的。
-
为了给一个文件加锁,进程必须要拥有一个引用该文件的文件描述符(即在实践中它必须要拥有打开文件的权限)。
-
对 Internet domain socket 的访问(即连接或发送数据报)没有限制。如果有需要的话,必须要在应用程序中实现访问控制。

4.6 持久性
术语持久性是指一个 IPC 工具的生命周期。持久性有三种。
- 进程持久性:只要存在一个进程持有进程持久的 IPC 对象,那么该对象的生命周期就不会终止。如果所有进程都关闭了对象,那么与该对象的所有内核资源都会被释放,所有未读取的数据会被销毁。管道、FIFO 以及 socket 是进程持久的 IPC 工具。
- 内核持久性:只有当显式地删除内核持久的 IPC 对象或系统关闭时,该对象才会销毁。这种对象的生命周期与是否有进程打开该对象无关。这意味着一个进程可以创建一个对象,向其中写入数据,然后关闭该对象(或终止)。在后面某个时刻,另一个进程可以打开该对象,然后从中读取数据。具备内核持久性的工具包括 System V IPC 和POSIX IPC。
- 文件系统持久性:具备文件系统持久性的 IPC 对象会在系统重启的时候保持其中的信息,这种对象一直存在直至被显式地删除。唯一一种具备文件系统持久性的 IPC 对象是基于内存映射文件的共享内存。
4.7 性能
在一些场景中,不同 IPC 工具的性能可能存在显著的差异。但一般不会对它们的性能进行比较,其原因如下。
-
在应用程序的整体性能中,IPC 工具的性能的影响因素可能不是很大,并且确定选择何种 IPC 工具可能并不仅仅需要考虑其性能因素。
-
各种 IPC 工具在不同 UNIX 实现或 Linux 的不同内核中的性能可能是不同的。
-
最重要的是,IPC 工具的性能可能会受到使用方式和环境的影响。相关的因素包括每个 IPC 操作交换的数据单元的大小、IPC 工具中未读数据量可能很大、每个数据单元的交换是否需要进行进程上下文切换、以及系统上的其他负载。
如果 IPC 性能是至关紧要的,并且不存在应用程序在与目标系统匹配的环境中运行的性能基准,那么最好编写一个抽象软件层来向应用程序隐藏 IPC 工具的细节,然后在抽象层下使用不同的 IPC 工具来测试性能。
相关文章:
Linux/AndroidOS中进程间的通信线程间的同步 - IPC方式简介
前言 从来没有总结过Linux/Android系统中进程间的通信方式和线程间的同步方式,这个专栏就系统总结讨论一下。首先从标题可知,讨论问题的主体是进程和线程、通信和同步;在这里默认你理解进程和线程的区别。通信和同步有什么概念上的区别&…...
Windows:注册表配置应用
0、简介 本篇博客记录一下,日常的系统注册表配置选项,以防再次遇到问题不知如何解决。 1、开机启动配置 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run :: 此位置存储了所有用户登录时需要启动的程序。 在该项下新建字符串值&#…...
升级xcode16之后react-native-zip-archive不兼容,unsupported option ‘-G‘
问题 升级xcode到16之后,xcode build报错:unsupported option -G for target x86_64-apple-ios13.4-simulator (in target RNZipArchive from project Pods) 出现原因 在 React Native 项目中,当你将 Xcode 升级到 16 后,可能会遇到 RNZipArchive 相关的编译错误,特别是…...
WebXR教学 05 项目3 太空飞船小游戏
准备工作 自动创建 package.json 文件 npm init -y 安装Three.js 3D 图形库,安装现代前端构建工具Vite(用于开发/打包) npm install three vite 启动 Vite 开发服务器(推荐)(正式项目开发) …...
网页在浏览器中显示的原理(简要)
网页在浏览器中显示的过程是一个复杂的多阶段流程。 1. 输入URL并发起请求 用户在地址栏输入URL并回车 浏览器检查缓存(DNS缓存、页面缓存等) 如果没有缓存,通过DNS解析获取服务器IP地址 建立TCP连接(三次握手) 发…...
rl中,GRPO损失函数详解。
文章目录 **一、GRPO损失函数的设计背景****二、代码逐行解析****三、关键组件详解****1. 对数概率与KL散度计算****2. 优势值与策略梯度****3. 掩码与平均损失****四、训练动态与调参建议**在TRL(Transformer Reinforcement Learning)库中,GRPO(Group Relative Policy Opt…...
【Java面试笔记:基础】12.Java有几种文件拷贝方式?哪一种最高效?
在 Java 中,文件拷贝可以通过多种方式实现,不同方式的性能和适用场景有所差异。 1. Java 文件拷贝方式 传统 IO 方式 使用 FileInputStream 和 FileOutputStream,通过循环读取和写入数据实现文件拷贝。 示例代码: try (InputStream is = new FileInputStream("sou…...
【leetcode】3524 求出数组的X值1
题目链接 题目描述 给你一个正整数数组 nums 和一个正整数 k。 你可以对数组执行一次操作:移除不重叠的前缀和后缀(可以为空),留下一个连续非空子数组。 对于每一种留下的子数组,计算: (该子数组的乘积…...
达梦统计信息收集情况检查
查询达梦某个对象上是否有统计信息 select id,T_TOTAL,N_SMAPLE,N_DISTINCT,N_NULL,BLEVEL,N_LEAF_PAGES,N_LEAF_USED_PAGES,LAST_GATHERED from sysstats where id IN (select id from sysobjects where upper(name)upper(&objname));可能有系统对象,可以增加…...
1️⃣5️⃣three.js_GUI辅助调试器
15、GUI辅助调试器 3D虚拟工厂在线体验 GUI辅助调试器将原本需要修改代码调整参数并刷新页面的操作,简化为直接在GUI中实时调整,实现所见即所得的效果。 导入GUI 库 //引入GUI辅助调试器 import {GUI } from three/addons/libs/lil-gui.module.min.js创建GUI辅助调试器对象 c…...
【matlab】气泡图的应用
【matlab】气泡图的应用 .rtcContent { padding: 30px; } .lineNode {font-size: 12pt; font-family: "Times New Roman", Menlo, Monaco, Consolas, "Courier New", monospace; font-style: normal; font-weight: normal; } clear load zb_equi.mat load …...
@Configuration注解对应实现implements WebMvcConfigurer的配置不生效问题。
检查项目是否有其他配置实现了 extends WebMvcConfigurationSupport,如果有就是这个配置导致实现implements WebMvcConfigurer的配置不生效。 我的问题项目有imgconfig,和webconfig Configuration public class ImgConfig extends WebMvcConfigurationS…...
飞帆控件:在编辑模式下额外加载的库
飞帆是一个自由的控件设计平台。在飞帆中,我们可以很方便地创建基于 Vue 2 组件的控件,并使用控件来搭建网页。 他山之石,可以攻玉。在创建控件中,使用 js 、css 依赖库能让我们的控件更强大。 有些时候,在编辑模式下…...
【k8s】docker、k8s、虚拟机的区别以及使用场景
一、Docker (一)概念 Docker 是一个开源的应用容器引擎,允许开发者将应用及其依赖打包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可实现虚拟化。 (二)隔离性 Docker 的隔离…...
Super-Vlan和MUX-Vlan的原理、配置、区别
Super-Vlan 原理 Super-Vlan也叫Aggregate-Vlan。 一般的三层交换机中,通常是采用一个VLAN对应一个vlanif接口的方式实现广播域之间的互通,这在某些情况下导致了IP地址的浪费。因为一个VLAN对应的子网中,子网号、子网定向广播地址、子网缺…...
Docker容器化技术全栈指南:从基础运维到企业级实践
Docker容器化技术全栈指南:从基础运维到企业级实践 一、Docker核心价值与日常运维全景 1. 容器化革命性优势 维度传统虚拟化Docker容器启动速度分钟级(完整OS引导)秒级(共享内核)资源消耗每个VM需独立OS(…...
Python 赋能区块链教育:打造去中心化学习平台
Python 赋能区块链教育:打造去中心化学习平台 引言 区块链技术正在重塑全球多个行业,而教育领域也不例外。传统的在线学习平台往往依赖中心化存储和管理模式,导致数据安全、用户隐私、资源共享等问题难以解决。而随着 Web 3.0 的发展,区块链在教育场景中的应用逐渐受到关…...
el-table怎么显示 特殊单元格的值
1. 在 el-table-column 上绑定了 formatter 方法 formatEntityName ,它会对每一行该列的数据( cellValue )进行处理。 2. 在 formatEntityName 方法中,尝试对传入的 cellValue 进行 JSON.parse 操作,并根…...
Java中实现单例模式的多种方法:原理、实践与优化
单例模式(Singleton Pattern)是设计模式中最简单且最常用的模式之一,旨在确保一个类只有一个实例,并提供全局访问点。在 Java 开发中,单例模式广泛应用于配置管理、日志记录、数据库连接池和线程池等场景。然而&#x…...
2025-04-23 Python深度学习3——Tensor
文章目录 1 张量1.1 数学定义1.2 PyTorch中的张量 2 创建 Tensor2.1 直接创建**torch.tensor()****torch.from_numpy()** 2.2 依据数值创建**torch.zeros() / torch.zeros_like()****torch.ones() / torch.ones_like()****torch.full() / torch.full_like()****torch.arange() …...
在统信UOS/麒麟Kylin OS操作系统中配置APT和GIT代理
在统信UOS/麒麟Kylin OS操作系统中配置APT和GIT代理 在内网环境中,直接访问外部资源可能会受到限制,这时候配置APT和GIT的代理就显得尤为重要。本文将详细介绍如何在统信UOS和麒麟Kylin OS操作系统中配置APT和GIT的代理。 为什么需要配置APT和GIT代理&…...
spring,spring boot, spring cloud三者区别
Spring Framework vs Spring Boot vs Spring Cloud 1. Spring Framework 定位:基础框架,提供核心的IoC容器、AOP、事务管理、数据访问、Web MVC等能力。特点: 模块化设计:可单独使用某些模块(如仅用Spring JDBC&…...
第十七讲、Isaaclab中使用操作空间控制器
0 前言 官方教程:https://isaac-sim.github.io/IsaacLab/main/source/tutorials/05_controllers/run_osc.html IsaacsimIsaaclab安装:https://blog.csdn.net/m0_47719040/article/details/146389391?spm1001.2014.3001.5502 有时候,仅使用…...
基于SpringBoot的校园二手商品在线交易系统+含项目运行说明文档
基于SpringBoot的校园二手商品在线交易系统含项目运行说明文档 专注校园二手交易平台是一个基于Java的在线市场,专为学生设计,便于买卖二手商品。平台提供全面的用户管理功能,包括学生、管理员和二手商品卖家账户管理。商品管理功能允许用户…...
电商行业下的Java核心、Spring生态与AI技术问答
电商行业下的Java核心、Spring生态与AI技术问答 在互联网大厂求职的Java程序员马架构,今天参加了一场关于电商行业的技术面试。以下是面试官和马架构之间的5轮提问和回答。 第一轮提问 问题1:请简要描述一下电商系统中的高并发处理方案。问题2&#x…...
面向电力变压器的声纹智能诊断系统简析
面向电力变压器的声纹智能诊断系统是一种利用声纹识别技术对电力变压器运行状态进行实时监测和故障诊断的系统。以下是其简要分析: 系统组成 感知层:主要由声纹传感器和振动传感器组成。声纹传感器一般采用高灵敏度麦克风,用于采集变压器向…...
《浔川AI翻译v6.1.0问题已修复公告》
《浔川AI翻译v6.1.0问题已修复公告》 尊敬的浔川AI翻译用户: 感谢您对浔川AI翻译的支持与反馈!我们已针对 **v6.1.0** 版本中用户反馈的多个问题进行了全面修复,并优化了系统稳定性。以下是本次修复的主要内容: 已修复问题 ✅…...
详解springcloud gateway工作原理、断言、filter、uri、id、全局跨域、globalfilter等以及关键源码实现
1.gateway概念 网关就是当前微服务项目的"统一入口"程序中的网关就是当前微服务项目对外界开放的统一入口所有外界的请求都需要先经过网关才能访问到我们的程序提供了统一入口之后,方便对所有请求进行统一的检查和管理 2. 网关的主要功能 将所有请求统一经过网关网…...
C++面向对象特性之继承篇
C语音是面向过程的语言,而C在其之上多了面向对象的特性,面向对象三大特性:封装性、继承性、多态性。今天主包来讲讲自己学到的关于C继承特性的知识。 一、继承是什么 继承是提高代码复用的一种重要手段。正如C的模版、泛型编程等等都是为了实现代码复用…...
【Java设计模式及实践学习-第4章节-结构型模式】
第4章节-结构型模式 笔记记录 1. 适配器模式2. 代理模式3. 装饰器模式4. 桥接模式5. 组合模式6. 外观模式7. 享元模式8. 总结 1. 适配器模式 2. 代理模式 3. 装饰器模式 4. 桥接模式 5. 组合模式 6. 外观模式 7. 享元模式 Java语言中的String字符串就使用了享元模式&…...
