线程

走进 Java Volatile 关键字

核能气质少年 提交于 2020-03-17 07:50:43
Java Volatile 关键字是一种轻量级的数据一致性保障机制,之所以说是轻量级的是因为 volatile 不具备原子性,它对数据一致性的保障体现在对修改过的数据进行读取的场景下(也就是数据的可见性)。比起对读操作使用互斥锁, volatile 是一种很高效的方式。因为 volatile 不会涉及到线程的上下文切换,以及操作系统对线程执行的调度运算。同时 volidate 关键字的另一个功能是解决“指令重排序问题”。 Volatile 可见性承诺 Java volatile关键字保证了跨线程更改线程间共享变量的可见性。这可能听起来有点抽象,让我们详细说明一下。 在多线程应用程序中,线程对 non-volatile 变量进行操作,出于性能原因,每个线程在处理变量时,可以将它们从主内存复制到CPU缓存中。如果你的计算机包含一个以上的CPU,每个线程可以在不同的CPU上运行。这意味着,每个线程可以将同一个变量复制到不同CPU的CPU缓存中。这就和计算机的组成和工作原理息息相关了,之所以在每一个 CPU 中都含有缓存模块是因为出于性能考虑。因为 CPU 的执行速度要比内存(这里的内存指的是 Main Memory)快很多,因为 CPU 要对数据进行读、写的操作,如果每次都和内存进行交互那么 CPU 在等待 I/O 这个过程中就消耗了大量时间

利用多线程通过对业务优化实现性能优化—— 性能优化利用 Thread 的 join

你。 提交于 2020-03-17 07:37:25
我们可以使用 join方法做到将程序并行。 举个例子:我们在开发过程中往往会遇到这样的场景,就是一个非常复杂的业务逻辑里边,比方说订票,如果说飞机票和火车票作为一个组装行程。比方说我要去 莫斯科,我人在A地,然后我可以选择去B地坐飞机,但是A地到B地这一段,我想做高铁。如果这作为一个订单的话,就意味着,下单过程需要到12306去扣火车票,然后到航空公司去扣飞机票。 对于上边的下单的过程,可以选择串行,比方说先去 12306扣火车票,再去航空公司扣机票,最终将结果返回。其实我们知道,整个下单过程是非常复杂的,都要检验什么的,如果串行操作的话,是非常耗时的。 这个时候我们可以使用多线程来处理我们的下单过程,线程A去处理扣火车票,线程B去处理扣飞机票。最后将最终的结果返回。 通过上边的问题的描述,其实就能引出一个问题,那就是我们需要等两个线程执行完成以后才能返回结果。我们如何知道线程A有没有执行完成呢,我们如何知道B执行完了呢,我们什么时候才放回结果呢? 这个时候就可以使用 Thread 的 join()方法,它可以做到,让主线程创建完A和B线程以后,等待A 和 B 线程执行结束以后再开始执行。怎么做到呢? 就是 主线程分别给A和B都进行Join() 下边来写一个例子模仿,这样的场景问题: /** * @author angus * @create 2020-03-14 15:59 */

Python之线程

心已入冬 提交于 2020-03-17 06:34:56
为什么需要线程 进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上: 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。 什么是线程 线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元,也是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 线程与进程的区别: 根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位 在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。 所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

学习心得_06

孤人 提交于 2020-03-17 06:13:43
这周是已经第六周了了,javaSE部分已经学了一大半了,随着学习的不断深入我对JAVA语言的理解也上了一个台阶,但是难度也随之增加;这周主要学习了异常以及异常的处理,自定义异常;多线程的相关内容,包括两种创建线程的方式、线程的三种状态;线程的安全、关于线程的两个经典问题、线程通信;当然最重要的还是高级线程,介绍了线程池,如何获取线程池以及相应的接口。 来源: CSDN 作者: Willing 卡卡 链接: https://blog.csdn.net/weixin_42601136/article/details/104887474

[Mark] KVM 虚拟化基本原理

混江龙づ霸主 提交于 2020-03-17 06:06:53
X86 操作系统是设计在直接运行在裸硬件设备上的,因此它们自动认为它们完全占有计算机硬件。x86 架构提供四个特权级别给操作系统和应用程序来访问硬件。 Ring 是指 CPU 的运行级别,Ring 0是最高级别,Ring1次之,Ring2更次之…… 就 Linux+x86 来说, 操作系统(内核)需要直接访问硬件和内存,因此它的代码需要运行在最高运行级别 Ring0上,这样它可以使用特权指令,控制中断、修改页表、访问设备等等。 应用程序的代码运行在最低运行级别上ring3上,不能做受控操作。如果要做,比如要访问磁盘,写文件,那就要通过执行系统调用(函数),执行系统调用的时候,CPU的运行级别会发生从ring3到ring0的切换,并跳转到系统调用对应的内核代码位置执行,这样内核就为你完成了设备访问,完成之后再从ring0返回ring3。这个过程也称作用户态和内核态的切换。 那么,虚拟化在这里就遇到了一个难题,因为宿主操作系统是工作在 ring0 的,客户操作系统就不能也在 ring0 了,但是它不知道这一点,以前执行什么指令,现在还是执行什么指令,但是没有执行权限是会出错的。所以这时候虚拟机管理程序(VMM)需要避免这件事情发生。 虚机怎么通过 VMM 实现 Guest CPU 对硬件的访问,根据其原理不同有三种实现技术: 1. 全虚拟化 2. 半虚拟化 3. 硬件辅助的虚拟化 1

线程的并发工具类 ---CountDownLatch的作用、应用场景和实战

送分小仙女□ 提交于 2020-03-17 05:53:05
CountDownLatch 中文名:闭锁,CountDownLatch 这个类能够使一个线程等待其他线程完成各自的工 作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动 所有的框架服务之后再执行。 CountDownLatch 是通过一个计数器来实现的,计数器的初始值为初始任务 的数量。每当完成了一个任务后,计数器的值就会减 1 CountDownLatch.countDown()方法 当计数器值到达 0 时,它表示所有的已 经完成了任务,然后在闭锁上等待 CountDownLatch.await()方法的线程就可以恢 复执行任务。 应用场景: 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。 例如,我们想测试一个单例类。如果我们创建一个初始计数为 1 的 CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次 countDown()方法就可以让所有的等待线程同时恢复执行。 开始执行前等待 n 个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有 N 个外部系统已经启动和运行了,例如处理 excel 中多个表单。 /** *类说明:演示CountDownLatch用法, * 共5个初始化子线程,6个闭锁扣除点,扣除完毕后,主线程和业务线程才能继续执行 */ public

临界区和C++使用方式

霸气de小男生 提交于 2020-03-17 04:05:52
一.临界资源 临界资源是一次仅允许一个进程使用的共享资源。 各进程采取互斥的方式,实现共享的资源称作临界资源。属于临界资源的硬件有,打印机,磁带机等;软件有消息队列,变量,数组,缓冲区等。诸进程间采取互斥方式,实现对这种资源的共享。 二.临界区: 每个进程中访问临界资源的那段代码称为临界区(criticalsection ) ,每次只允许一个进程进入临界区,进入后,不允许其他进程进入。不论是硬件临界资源还是软件临界资源,多个进程必须互斥的对它进行访问。多个进程涉及到同一个临界资源的的临界区称为相关临界区。使用临界区时,一般不允许其运行时间过长,只要运行在临界区的线程还没有离开,其他所有进入此临界区的线程都会被挂起而进入等待状态,并在一定程度上影响程序的运行性能。 三、优缺点 优点:效率高, 与互斥和事件这些内核同步对象相比,临界区是用户态下的对象,即只能在同一进程中实现线程互斥。因无需在用户态和核心态之间切换,所以工作效率比较互斥来说要高很多。 缺点:资源释放容易出问题 ,Critical Section不是一个核心对象,无法获知进入临界区的线程是生是死,如果进入临界区的线程挂了,没有释放临界资源,系统无法获知,而且没有办法释放该临界资源。 临界区是一种轻量级的同步机制,与互斥和事件这些内核同步对象相比,临界区是用户态下的对象, 即只能在同一进程中实现线程互斥

浅析Chrome的渲染流程(下)

浪子不回头ぞ 提交于 2020-03-17 03:32:09
在浅析Chrome的渲染流程(上)中我们介绍了渲染流水线中的 DOM生成 、 样式计算 和 布局 三个阶段。今天我们来讲下渲染流水线后面的阶段。 分层 经过生成布局之后生成的布局树,将每个元素的具体位置信息都计算出来了,那么接下来是不是开始着手绘制页面了? 答案依然是否定的。 因为页面中有很多复杂的效果,比如一些复杂的3D变换、页面滚动,或者使用z-indexing做z轴排序等。为了更加方便地实现这些效果, 渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerThree) 。提到图层,大家最先应该想到的是PS软件。PS中图层是很常见的,比如将图片背景变成透明的,就需要先复制一个图层出来后,用滤棒清除掉图层中不需要的部分,然后应用到原始图像上,就可以生成一个具有透明背景的图片了。 要想直观地理解什么是图层,可以通过Chrome的 “开发者工具”,选择 “Layers” 标签,就可以可视化页面的分层情况,如下图: 如果找不到 “Layers” 这个标签,请参考下图: 从上面的第一张图可以看出,渲染引擎给页面分了很多图层,这些图层按照一定的顺序折叠加在一起,就形成了最终的页面。 现在你知道了浏览器的页面实际上被分成了很多图层,这些图层叠加后合成了最终的页面。那么这些图层和布局树节点的之间的关系是什么样子呢?请参考下图: 通常情况下,

IO的四种模型

折月煮酒 提交于 2020-03-17 02:19:45
Nio Io读写,读写都会涉及底层的read和write的使用。Read把内核缓冲区的内容复制到进程缓冲区。 外部设备的直接读写会涉及到系统的中断,发生系统中断时,会保存之前的进程和状态信息,等中断结束还要恢复之前的。 BIO(blocking io) 从线程发出读请求,线程会一直处于阻塞模式,缺点:会为每个连接配备一个线程,在高并发的场景下,需要大量的线程来维护网络连接,内存和线程切换消耗大。 NIO(None Blocking IO) 在内核缓冲区没有数据时,用户发起请求会立即返回, 为了读取最终的数据,用户IO会不断地发起IO调用 直到数据完整后,用户线程阻塞,直到用户线程获取到数据 缺点:轮询会消耗cpu的大量的时间。 IO Multiplexing (1) 进行read操作,就会将目标socket的网络连接提前注册到select/epoll选择器中去(selector)类中 (2) 通过查询的系统调用,就会返回一个就绪的socket列表,,用户进程调用了select,整个线程会被阻塞掉 (3) 获取到列表中的socket后,发起read系统调用,整个线程会被阻塞掉。直到读取到数据。 IO多路复用两种系统的操作:select/epoll 和 IO操作 优点:一个选择器查询线程可以同时监听几万个连接,不必创建和维护大量的线程 缺点:select/epoll是阻塞的

并发编程之ThreadLocal详解

冷暖自知 提交于 2020-03-17 01:26:16
某厂面试归来,发现自己落伍了!>>> ThreadLocal 什么是ThreadLocal: 它提供线程本地变量,如果创建一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的是自己本地内存中的变量,从而规避了线程安全问题。 API讲解: void set(T value)设置当前线程的线程局部变量的值; T get()该方法返回当前线程所对应的线程局部变量; void remove() 将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。 源码分析: ThreadLocal在使用的时候:对象实例与ThreadLocal变量的映射关系是由线程Thread来维护的。 上述解释:对象实例与ThreadLocal变量的映射关系是存放在一个Map中的,这个map是一个抽象的map并不是java.util中的map。该map是Thread类中的一个字段而已!而真正存放映射关系的map是ThreadLocalMap。 核心描述:当我们创建一个Thread时内部有一个ThreadLocalMap变量该变量又是一个内部类,其内部有包含一个Entry变量