例如:这就像我们同时读两本书,当我们在读一本英文的技术书时,发现某个单词不认识,于是便打开中英文字典,但是在放下英文技术书之前,大脑必须先记住这本书读到了多少页的第多少行,等查完单词之后 , 能够继续读这本书 。这样的切换是会影响读书效率的,同样上下文切换也会影响多线程的执行速度 。
如何减少上下文切换
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程 。
- 无锁并发编程: 多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash 算法取模分段,不同的线程处理不同段的数据 。
- CAS算法:Java的Atomic包使用CAS算法来更新数据,而不需要加锁 。
- 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理 , 这样会造成大量线程都处于等待状态 。
- 协程:在单线程里实现多任务的调度 , 并在单线程里维持多个任务间的切换 。
强烈建议多使用JDK并发包提供的并发原子类和工具类来解决并发问题 , 因为这些类都已经通过了充分的测试和优化 , 均可解决了上面提到的几个挑战 。8、Java内存模型(Java Memory Model)什么是JMM内存模型?
Java内存模型(即Java Memory Model,简称JMM) 。Java内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java内存模型是标准化的,屏蔽了底层不同计算机的区别 。
JMM本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式 。由于JVM运行程序的实体是线程 , 而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据 。而Java内存模型中规定所有共享变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问 。
线程对共享变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存 , 不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝,前面说过 , 工作内存是每个线程的私有数据区域 , 因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成,其简要访问过程如下图:

文章插图
关于JMM中的主内存和工作内存说明如下:
- 主内存
- 工作内存
启动2个线程,线程A读取主内存的共享变量数据,之后线程B修改共享变量数据,线程A无法感知:
package cn.itcast.thread;public class Test5 {// 定义flag属性private static boolean flag = false;public static void main(String[] args) throws InterruptedException {// 创建线程1new Thread(() -> {long num = 0;while (!flag){num++;}// 如果没有打?。?说明当前线程无法感知flag的修改System.out.println("num = " + num);}).start();// 休眠1000毫秒Thread.sleep(1000);// 创建线程2new Thread(() -> {// 修改flagflag = true;System.out.println("flag = " + flag);}).start();}} 运行效果:没有任务打印输出,上面的线程无法感知flag的修改 。9、Java并发编程三大特性Java并发编程三个特性: 可见性、原子性、有序性 。
推荐阅读
- “正科级”公务员退休后有多少钱?40年工龄的话,预计是这个数
- 女人对你有好感,哪怕嘴上不说,这7个肢体语言也藏不住
- “无性婚姻”有多可怕?听听3个过来人的故事,希望你能引以为戒
- 家里放了几年的红茶、绿茶、普洱茶,还能喝吗?医生告诉你实话
- 求求你们别再换脸了,就像好好的一盘菜吃出苍蝇的感觉!
- 拒认儿子巴图20年,晚年态度翻转,是居心叵测,还是真后悔?
- 教你自己制作花生酱,教你自制花生酱
- 微博该咋得才可以删除评论,为什么微博评论删除后还有显示
- 《我知道我爱你》热播:和冬天适配的偶像剧
- 李善均离世早有端倪?留下遗书后离家,现场有点燃闪电弹的痕迹
