java 中的多线程在代码层面是通过 new 多个 Thread 或是线程池实现的,这只是表象,我们需要继续审图探究。最终的计算任务是由 CPU 完成的,那么我们只要知道 CPU 如何调度 Thread 的就行了,这就引出了 CPU 时间这个概念
无论是单核还是多核 CPU 都是支持多线程的,CPU 通过给每个线程分配 CPU 时间片来实这个机制,这个时间片非常短,所以 CPU 通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms)
然后我们再想一想,我们计算的数据存在内存,但是 CPU 不在内存中计算数据,而是在 CPU 所属的寄存器中计算任务,这就涉及到 内存和 CPU 寄存器相互交互数据了。一个时间片段很短,很大可能一个线程的任务完不成,但是在这个 CPU 时间段结束后由别的线程抢到了隐形机会,那么 CPU 就得执行别的线程的任务,此时上一个线程未完成的任务的数据需要保存起来,然后加载下一个任务的数据进来,这就是线程上下问的切换
java 的这种多线程机制由于涉及线程的上下文操作会带来一个性能问题,线程的上下文切换和线程对象的创建是很消耗资源的
2个加减法循环在串行和并行时的性能对比,只有在百万次时他们的性能在相容,百万次以下,并行没有性能上的优势,所以在 rxjava 的线程池线程设计在大型就算任务时,线程池线程数量 =cpu 内核数,io 等非计算耗时任务时线程池线程数量无显示
那么如何减少上下文切换:
-
无锁并发编程
无锁并发编程.当任何特定的运算被阻塞的时候,所有CPU可以继续处理其他的运算。换种方式说,在无锁系统中,当给定线程被其他线程阻塞的时候,所有CPU可以不停的继续处理其他工作。无锁算法大大增加系统整体的吞吐量,因为它只偶尔会增加一定的交易延迟。大部分高端数据库系统是基于无锁算法而构造的,以满足不同级别 -
CAS 算法
Java提供了一套原子性操作的数据类型(java.util.concurrent.atomic包下),使用CAS算法来更新数据,不需要加锁。如:AtomicInteger、AtomicLong等 -
使用最少线程
避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态 -
协程
在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换,kotlin ,goland 都支持协程
网友评论