1.上下文切换
上下文切换说的是CPU在执行不同任务之间的切换过程叫做上下文切换(若是体现在线程上就是线程状态变更那么就是一次上下文切换)。上下文切换是需要耗费时间的,这就是我们在并发编程中要考虑的情况若是上下文切换时间太长那么多线程反而变慢了。
下面是测试代码:
/** * Created by coffice on 2017/10/20. */ public class SimpleTest { private static final long count = 100000000; private static void concurrency () throws InterruptedException { long start = System.currentTimeMillis(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { int a = 0; for (long i = 0; i < count; i++) { a += 5; } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { int a = 0; for (long i = 0; i < count; i++) { a += 5; } } }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); long end = System.currentTimeMillis(); System.out.println("concurrency: " + (end-start) ); } private static void serial () { long start = System.currentTimeMillis(); int a = 0; for (long i = 0; i < count; i++) { a += 5; } int b = 0; for (long i = 0; i < count; i++) { b += 5; } long end = System.currentTimeMillis(); System.out.println("serial: " + (end-start) ); } public static void main (String args[]) throws InterruptedException { concurrency(); serial(); } }测试结果
循环次数 | 串行执行时间 | 并发执行时间 | 并发比执行 |
1亿 | 74 | 40 | 快 |
1千万 | 11 | 7 | 快 |
1百万 | 6 | 5 | 慢 |
10万 | 3 | 3 | 一样 |
1万 | 0 | 1 | 慢 |
当运行次数很少的时候,上下文切换影响比重就大很多,那么如何解决这个问题,很显然就需要减少上下文切换的次数。线程从wating->runnable就要切换一次上下文,只要减少线程的waiting即可避免多的上下文切换。
- 无锁并发
- CAS 算法代替锁(比较并交换算法)
AtomicInteger integer = new AtomicInteger(); final boolean b = integer.compareAndSet(1, 2);
- 线程不能创建太多,所以多数以线程池来管理
3. synchronized
3.1 偏向锁
它会偏向于第一个访问锁的线程,如果在接下来的运行过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不需要触发同步。
如果在运行过程中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会尝试消除它身上的偏向锁,将锁恢复到标准的轻量级锁。(偏向锁只能在单线程下起作用)因此 流程是这样的 偏向锁->轻量级锁->重量级锁
3.2 轻量级锁
3.2.1 自旋
遇到竞争时我先不阻塞,我先自我陶醉一下,看看在陶醉时间内能不能获得竞争锁,不成功再阻塞(这对那些执行时间很短的代码块来说有非常重要的性能提高,在这短时间内自旋能够获取竞争锁),尽量降低阻塞的可能性进而减少上下文切换,提高效率,因此自旋的时间应当小于一次上下文切换时间。
1.6以后引入了 "偏向锁"和 "轻量级锁"加上重量级锁一共3种锁,锁一共4种状态 由低到高:无状态锁、偏向锁状态、轻量级锁和重量级锁,这几个状态随着竞争逐渐升级。
锁 | 优点 | 缺点 | 使用场景 |
偏向锁 | 加锁和解锁不需要额外消耗,和执行非同步方法相比仅存在纳秒级差距 | 若线程存在竞争则会带来额外的锁撤销的消耗 | 适用于一个线程访问同步模块 |
轻量级锁 | 竞争的线程不会阻塞,提高线程访问速度 | 如果始终得不到锁竞争的线程,使用自旋会消耗CPU | 追求响应时间,同步块执行速度快 |
重量级锁 | 竞争线程不使用它自旋,不消耗CPU | 线程阻塞响应时间缓慢,同步块执行时间长 | 追求吞吐量 |
相关推荐
线程是程序执行的最小单元,一个进程可以包含多个线程,它们共享同一块内存空间,通过上下文切换实现并发执行。Java中的`Thread`类提供了创建和管理线程的基本功能,而`Runnable`接口则提供了一种无需继承特定类的...
自旋锁利用了CPU空转等待,减少了线程上下文切换的开销。公平锁和非公平锁的区别在于线程获取锁的顺序。读写锁(如ReentrantReadWriteLock)允许多个读操作并行执行,但写操作是独占的。 9. 并发问题和解决方案 ...
- **减少上下文切换**:合理使用线程池,减少线程创建的数量。 ### 六、并发工具类与实用技巧 #### 6.1 CyclicBarrier与CountDownLatch - **CyclicBarrier**:可以让一组线程等待至某个状态之后再全部同时执行。 -...
因此,优化线程数量以减少不必要的上下文切换是提高并发性能的重要手段。 在实际应用中,我们还需要考虑线程安全问题,例如使用`synchronized`、`volatile`、`Atomic`类或Lock来保证数据一致性。此外,合理使用...
* 上下文切换是什么? 线程的基本操作 * 创建线程的四种方式 * 线程的run()和start()有什么区别? * 什么是Callable和Future? 线程的状态和基本操作 * 线程的生命周期及五种基本状态 * 什么是线程的阻塞状态? ...
- 并发并不意味着多线程,启动过多线程可能会导致上下文切换开销增加,反而降低整体性能。理想的线程数量应基于硬件资源和具体任务来确定。 2. **多线程并发实现**: - 单核处理器也可以通过时间片分配实现多线程...
9. **线程局部变量**:ThreadLocal是线程绑定的变量,每个线程都有自己的副本,互不影响,常用于缓存或者存储线程相关的上下文信息。 10. **并发设计模式**:如生产者消费者模式、读写锁模式、双端队列模式等,都是...
什么是上下文切换? 线程和进程区别 什么是线程和进程? 创建线程有哪几种方式?,如何避免线程死锁 线程的 run()和 start()有什么区别? 什么是 Callable 和 Future? 线程的调度策略 sleep() 和 wait() 有什么区别...
并发编程的三要素是:线程、进程和上下文切换。线程是操作系统中的一种基本执行单元,进程是操作系统中的一种基本资源分配单元。上下文切换是指操作系统在切换线程或进程时所需的时间和资源开销。 在Java程序中,...
10. **并发性能优化**:书中会讨论如何通过调整并发策略、合理使用线程和资源来提高并发性能,包括避免过多的上下文切换、合理分配线程数量等。 通过对《Java并发编程实践》的深入学习,开发者可以更好地掌握Java...
本文主要讨论了线程和进程、线程上下文切换、并发与并行的区别,以及多线程环境下的一些问题,如线程安全、死锁等。 首先,线程和进程是操作系统中两个基本的执行单元。进程是程序运行的基本单位,每个Java程序运行...
通过合理使用线程池、避免不必要的同步、优化线程上下文切换,可以显著提升程序性能。 总的来说,《Java并发编程实战》将涵盖上述多个方面,通过实例解析和最佳实践指导,帮助开发者提升并发编程技能,解决实际项目...
并发通常涉及线程的调度和上下文切换,而并行则更多地关注任务的分解和数据的并行处理。 总的来说,Java并发编程是一门深奥的学问,需要深入理解线程的本质、并发模型、同步机制以及性能优化策略,才能编写出高效、...
第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解...
1. **线程**: Java中的线程是程序执行的基本单位,每个线程都有自己的堆栈空间和执行上下文。 - 创建线程的方法有两种:继承`Thread`类或实现`Runnable`接口。 - `Thread`类提供了多种控制线程的方法,如`start()`...
- 性能开销:由于同步会带来上下文切换和锁竞争,所以过多使用`synchronized`可能导致性能下降。 - 无法中断:等待获取锁的线程无法被中断,除非调用`interrupt()`方法或者抛出异常。 - 不可中断的阻塞:`...
- **适应性⾃旋(Adaptive Spinning)**:根据系统负载动态调整自旋等待的时间,以平衡锁等待和上下文切换的代价。 理解并发和并行的区别也很重要。并发是指在一个处理器上交替执行多个任务,而并行则是指在多个...
根据提供的标题、描述以及部分上下文内容,我们尝试从中提炼出与Java并发相关的知识点。由于提供的内容大部分似乎与Java并发主题不直接相关,我们将重点放在标题和描述上,并结合一些基本的Java并发概念来展开讨论。...
- 上下文切换:操作系统需要在多个线程间切换,导致额外的性能开销。 - 线程安全问题:多个线程操作共享资源可能会引发不一致的结果。 - 死锁:多个线程互相等待对方释放资源,导致程序无法继续执行。 4. 并发编程...