并发与并行的区别【图解+小例子】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:容易混淆的点

并行和并发,很多时候会被混淆理解为:多个线程或进程同时执行;单纯从表象来看的话,都是为了提高处理效率,但实际上区别还是很大的;


提示:以下是本篇文章正文内容,下面案例可供参考

一、初步理解

  • 并行是指的多个任务/事件在【同一时刻】发生;并发则是指的多个任务/事件在【同一时间区间内】交替发生;
  • 并行与并发的作用对象不一样:并行是【不同实体】执行的多个事件,并发是【同一实体】执行的多个事件;

有一定基础的话,似乎也能够理解;单从字面意思上,并行是真正意义上的同一时刻上的进行;并发则是为了提高对单个实体的利用效率;下面我再通俗说明一下二者的区别;

二、深入理解

1.并发

早期的计算机cpu是单核的,一个CPU在同一时间只能执行一个进程,当系统中有多个进程时,只能执行完一个进程后,才能执行下一个;
但是进程处理的过程中,会涉及到很多IO操作,而这个IO操作又很耗时,这个时候,CPU就只能干等着,CPU的资源就空闲在那里,只能等IO操作完了之后,CPU才能继续工作。
为了提高CPU的利用率,就提出了【并发】这个一概念,并落地了对应的cpu的利用算法,当一个任务在进行IO操作的时候,CPU去做别的任务,这下就大大提高了单核CPU的效率;
在这里插入图片描述
早期电脑多任务执行的时候(开着浏览器,开着千千静听,开着魔兽),看着像是同一时刻在进行,其实是这颗单核cpu在疯狂的【切换执行】,如果你这个时候,又打开了劲舞团就估计卡死了,单核cpu已经忙炸了;

2.并行

后来cpu有了双核之后,每个核心就可以【独立执行】一项任务,比如你打开了qq音乐,又打开了魔兽;那么就是一个核心执行QQ音乐,另一个核执行魔兽这个进程,各管各的,这个时候,两个程序是在同一时刻执行的;
在这里插入图片描述

3.并行+并发

如果cpu的核数小于当前的进程任务数,就需要所有的核心又要进行疯狂切换穿插执行了,这就是两种概念互补到达的高效执行;

总结:一个例子

结合上文的说明,举个例子:
【初期】早年,让张三这个单身汉开小餐馆,张三脑瓜子呆呆的,做事情一定要一件一件来,首先煮饭,煮饭是需要时间的,他就看着高压锅,傻傻的等,一顿年夜饭做好了,客人也都凉了;
后来张三就反思,这样做的确很傻;
【中期】前年由于早年的经历,学会了穿插去做事情,比如煮好饭之后,不再傻等饭熟,而是利用这个空闲的时间,去把菜洗好,切好…, 果然,做一顿饭的效率大大提高; 【一个人在穿插的做事,就是并发】
后来客人太多了,出菜效率还是不够;
【现在】张三就娶了一个老婆,张三也把前年穿插的经验告诉了他老婆,做一端饭,就两个人同时分工进行,张三洗米煮饭的时候,她老婆在洗菜切菜,如果这是用客人来,她老婆还能放下手上的事儿,迎接一下;小餐馆就能开心的办下去了;
【两个人同一时刻都在做事,就是并行,如果每个人都知道穿插着做事儿,就是并行+并发,大大提高效率】

<think>我们正在讨论Java中静态同步方法非静态同步方法的并发执行行为。具体问题是:它们是否可以同时执行,是否存在锁竞争? 根据引用内容,我们可以总结以下关键点: 1. **锁对象不同**: - 静态同步方法使用类的Class对象作为锁(即 `类名.class`)。 - 非静态同步方法使用当前实例对象(即 `this`)作为锁。 2. **锁对象独立性**: - 因为静态同步方法非静态同步方法使用的是不同的锁对象(一个是类对象,一个是实例对象),所以它们之间不会发生锁竞争。也就是说,一个线程在执行静态同步方法时,另一个线程可以同时执行非静态同步方法,因为它们获取的是不同的锁。 3. **静态同步方法之间的锁竞争**: - 所有静态同步方法都使用同一个类对象作为锁。因此,如果一个线程正在执行一个静态同步方法,那么其他线程在执行同一个类的任何静态同步方法时都会被阻塞。 4. **非静态同步方法之间的锁竞争**: - 对于同一个实例对象,多个非静态同步方法会使用同一个锁(即该实例对象)。因此,如果一个线程正在执行该实例的某个非静态同步方法,那么其他线程在执行该实例的任何非静态同步方法时都会被阻塞。 - 但是,不同的实例对象之间不会发生锁竞争。也就是说,一个线程在执行实例A的非静态同步方法时,另一个线程可以同时执行实例B的非静态同步方法。 5. **同步代码块的情况**: - 如果使用同步代码块,显式指定锁对象,那么锁竞争情况取决于使用的锁对象。 - 例如,在非静态方法中使用 `synchronized(this.getClass())`,那么它将静态同步方法使用相同的锁(类对象),因此它们之间会发生锁竞争。 现在,我们通过一个例子来验证静态同步方法非静态同步方法是否可以同时执行: 引用[5]中的示例代码: ```java public class Phone { public static synchronized void sendEmail() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":send email"); } public synchronized void sendCall() { System.out.println(Thread.currentThread().getName() + ":send call"); } public void hello() { System.out.println(Thread.currentThread().getName() + ":send hello"); } } class LockDemo { public static void main(String[] args) { Phone phone = new Phone(); Phone phone2 = new Phone(); new Thread(() -> { phone.sendEmail(); // 注意:这里通过实例调用静态方法(不推荐,但允许) }, "aThread").start(); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { phone2.sendCall(); // 调用非静态同步方法 }, "bThread").start(); } } ``` 运行结果: ``` bThread:send call aThread:send email ``` 结果分析: - 线程aThread调用`phone.sendEmail()`(静态同步方法),它获取的是Phone类的Class对象的锁。 - 线程bThread调用`phone2.sendCall()`(非静态同步方法),它获取的是phone2实例对象的锁。 - 由于两个锁对象不同,因此两个线程可以同时执行,没有锁竞争。所以先输出bThread的信息(因为aThread睡眠了2秒,而bThread几乎立即执行),然后输出aThread的信息。 因此,结论是:**静态同步方法非静态同步方法可以同时执行,因为它们使用的锁对象不同,不存在锁竞争。** 但是,需要注意: - 如果在一个方法中同时使用类锁实例锁,那么它们之间不会相互阻塞,但可能会因为其他线程对同一锁的竞争而阻塞。 另外,引用[1][3]也明确指出: > 静态同步方法非静态同步方法之间是不会有竞态条件的。[^1] > 静态同步方法非静态同步方法不存在竟态条件,前者请求类的同步监视器,后者请求的实例的同步监视器。[^3] 所以,回答用户的问题:Java中静态同步方法非静态同步方法可以同时执行,不存在锁竞争。 最后,我们生成相关问题:</think>### Java静态同步方法非静态同步方法的并发行为分析 #### 🔒 锁机制差异 1. **静态同步方法** - 使用**类对象(Class对象)** 作为锁[^1][^3] - 示例:`public static synchronized void method()` - 锁对象 = `ClassName.class` 2. **非静态同步方法** - 使用**当前实例对象(this)** 作为锁[^1][^4] - 示例:`public synchronized void method()` - 锁对象 = `this` #### ⚡️ 并发执行结论 | **场景** | 是否可同时执行 | 是否存在锁竞争 | 原因 | |-----------------------------------|----------------|----------------|----------------------------------------------------------------------| | 静态方法 vs 非静态方法 | ✅ **是** | ❌ **否** | 锁对象不同:类锁(`Class`) vs 实例锁(`this`)[^1][^3] | | 不同实例的非静态方法 | ✅ **是** | ❌ **否** | 每个实例有独立锁(`this1` ≠ `this2`)[^5] | | 同一实例的非静态方法 | ❌ **否** | ✅ **是** | 共享同一实例锁(`this`) | | 静态方法 vs 静态方法 | ❌ **否** | ✅ **是** | 共享同一类锁(`Class`)[^1][^3] | | `synchronized(this.getClass())` vs 静态方法 | ❌ **否** | ✅ **是** | 显式指定类锁(`Class`),静态方法锁相同[^3][^4] | #### 🔍 关键验证实验(引用[5]代码分析) ```java // 线程A:调用静态同步方法 (类锁) new Thread(() -> phone.sendEmail()).start(); // 持有Phone.class锁 // 线程B:调用非静态同步方法 (实例锁) new Thread(() -> phone2.sendCall()).start(); // 持有phone2实例锁 ``` **执行结果**: ``` bThread:send call // 立即输出 aThread:send email // 2秒后输出 ``` **结论**: - 线程A持有`Phone.class`锁,线程B持有`phone2`实例锁 - 两线程**并行执行无阻塞**,证明无锁竞争[^5] #### 💡 核心原理图解 ```mermaid graph TD A[静态同步方法] -->|锁对象| B(ClassName.class) C[非静态同步方法] -->|锁对象| D(this实例对象) E[显式同步块] -->|synchronized(ClassName.class)| B E -->|synchronized(this)| D B --> F[全局唯一类锁] D --> G[每个实例独立锁] ``` #### ⚠️ 重要注意事项 1. **显式指定类锁** ```java // 以下代码静态方法存在锁竞争 synchronized(this.getClass()) { // 显式获取类锁 // 临界区代码 } ``` 2. **静态方法中禁止使用`this`锁** ```java public static void staticMethod() { synchronized(this) { // 编译错误!静态方法无this引用[^4] } } ``` 3. **跨实例静态方法互斥** ```java Phone p1 = new Phone(); Phone p2 = new Phone(); // 以下调用互斥(共享Phone.class锁) p1.sendEmail(); // 阻塞p2的同名调用 p2.sendEmail(); ``` #### 💎 总结 - ✅ **静态同步方法****非静态同步方法**可同时执行(无锁竞争) - ❌ **同类型方法之间**(静态↔静态 或 同实例非静态↔非静态)存在锁竞争 - 🔧 锁行为取决于**实际锁对象**而非方法修饰符
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值