java 及时释放内存_JMM(一):初识Java内存模型

在并发编程中,线程之间的通信是一个很关键的问题,而该问题解决方案主要可分为两大类:消息传递、共享内存。前者有以Erlang语言为代表的Actor模型,而后者中典型的则是Java语言。对于消息传递机制而言,线程之间必须通过发送消息以进行显式地通信。而同步过程则是隐式地,因为消息的发送必须在消息的接收之前;而对于共享内存机制来说,线程之间可以通过读、写内存中的公共状态来实现隐式地通信,但同步操作则需通过开发者显式地进行指定。可以看到由于Java的并发采用是共享内存机制,所以在谈多线程并发编程之前,需要对JMM(Java Memory Model)Java内存模型有一定的了解

9dd5b8ac09f0814c791a8c62d222edf2.png

abstract.png

CPU内存模型与缓存一致性问题

CPU内存模型

在谈论Java内存模型之前,我们先来了解下现代CPU内存模型。下面是一个双核CPU的组成示意图,每个CPU都包含一个独有的一级缓存,同时还有一个可被所有CPU共享的二级缓存。多级Cache的作用就是为了缓冲现代CPU与主内存Ram之间严重不匹配的速度

283e3a88912295d1d0b3142b360b5292.png

figure 1.jpeg

Cache Coherency 缓存一致性问题

双核甚至多核CPU的出现,使得多个线程可以在不同的CPU中执行,可以大大减少单核CPU由于频繁切换线程而引起的上下文切换开销。目前看来好像一切都是美妙的。但是很快人们发现,这会引发一个新的问题——Cache Coherency 缓存一致性问题

假设现在我们有两个线程A、B分别使用CPU #1、#2执行,其中在主内存Ram有一个共享变量a,其初始值为1

  • Step 1 : 线程A将变量a的值修改为2

线程A首先获取共享变量a值,由于两级缓存L1 Cache、L2 Cache均未命中,故只能从主内存Ram中加载;然后将a=1缓存到两级缓存中;最后线程A修改了变量a的值为2,并将其写入两级缓存、主内存中

c01c8c547b381357fd14cc9a67e8bbcd.pngfigure 2.jpeg

  • Step 2 : 线程B对变量a进行自增

线程B首先获取共享变量a值,二级缓存L2 Cache被命中,其值为2;然后对变量a自增变为3,并将其写入两级缓存、主内存中

67da6d119a8d0d52b47db678a8a1a294.pngfigure 3.jpeg

目前为止一切都是正常的,经过Step1、2两步操作后,主内存中变量a的值变为3,符合我们的预期

  • Step 3 : 线程A对变量a进行自增

线程A首先获取共享变量a值,一级缓存L1 Cache被命中,其值为2;然后对变量a自增变为3,并将其写入两级缓存、主内存中

e54cf65a41e4a6513c1108dde50a593b.pngfigure 4.jpeg

等等,好像哪里不对啊!在Step2后共享变量在主内存中已经是3了,那么Step3中线程A如果再次对其自增后,主内存中的变量a的值应该更新为4才对啊。但实际上执行完Step3后,主内存变量a的却依然是3

相信聪明的朋友可能已经看出来原因所在了,在Step2后,虽然主内存中变量a的值已经更新为3了,但是在CPU #1独有的L1 Cache中,变量a的值却还是2未被更新。换言之,由于各CPU内部Cache之间的不可见性,CPU无法感知到其他CPU Cache对数据所做的更新、修改,从而引发 Cache Coherency 缓存一致性问题

总线加锁

为了解决Cache Coherency 缓存一致性问题,早期是通过直接对主内存与共享Cache(即这里的L2 Cache)之间的总线加锁来解决的。在我们上面的例子中,线程A的工作就是将变量a修改为2,然后再对其自增;而B线程的工作是将变量a的值自增一次。现在假设依然是Step 1先执行,即线程A将主存中变量a的值修改为2了。由于总线加锁机制的存在,在线程A第一次从主存中加载值为1的变量a时,总线即会主存中变量a进行加锁,使得其他CPU(即这里的CPU #2的线程B)无法读、写该变量只等进行等待,直到线程A完成了对该变量的全部操作Step1、Step3——即先将变量a修改为2,再自增为3。当线程A将变量a的值3最终写入主内存后,总线才会将该锁释放。此时线程B才可以从主内存中加载变量a执行自增操作,并最终将a=4写入到主内存中(当然总线在此期间同样会再次对总线进行加锁,以保证CPU #2的线程B对其进行独占)。即在总线加锁的机制下,如果线程A先拿到总线锁,则线程A、B的任务执行顺序是Step1、Step3、Step2。虽然通过总线加锁的方式可以解决我们上面提到的缓存一致性问题,但是弊端同样显而易见,总线加锁会导致其他线程完全无法操作该变量,只能进行等待。换句话说,总线加锁的效率太低、开销太大,严重浪费了多核CPU的性能

MESI协议-缓存锁

为了解决总线加锁的弊端,现代CPU在访问Cache的过程中,可通过遵循一些协议来解决缓存一致性问题。典型地有Intel的MESI缓存一致性协议。在MESI协议中,当多个CPU从主内存加载同一个共享变量的数据并缓存到各自Cache后,一旦某个CPU修改了该变量在其缓存中的数据后,立刻将修改后的数据同步到主内存中。通过对Cache中该数据所在的缓存行加锁来阻止其他CPU同时修改主内存中该变量的数据,当主内存数据被修改完毕后即释放锁。与此同时,其他CPU可通过总线嗅探机制感知到该变量的数据变化从而将自己CPU内部相应的缓存数据失效。可以看到,MESI协议,一方面让CPU可以感知其他CPU中缓存数据的修改、变化来及时将自己Cache中的数据失效;另一方面只对缓存数据在回写到主内存的过程进行加锁,即使用缓存锁的方式,大大减小了锁的粒度,提高了多核CPU的利用率

Java Memory Model

有了前面CPU内存模型的引子,现在让我们回到正题来了解下什么是Java Memory Model(Java内存模型)。Java试图定义一种内存模型,其能够屏蔽各种硬件底层、操作系统的内存访问差异,以保证Java程序在各种平台下的一致的内存访问效果。而在JDK 1.5版本中通过实现JSR-133,Java内存模型才被真正地完善地成熟地建立起来了。所以本文所谈论的Java内存模型均是基于JSR-133而言的

Java内存模型规定共享变量存储在主内存中,当Java线程使用该共享变量时,需要先将其拷贝到该线程所属的工作内存中。换句话说,线程对共享变量的操作只能在该线程的工作内存中进行,而不能直接读写主内存中的变量。当然线程之间也无法直接访问对方工作内存中的变量,所以线程之间共享变量值的传递均需通过主内存来完成。其示意图如下所示,可以看到JMM在设计上与我们之前介绍的CPU内存模型有很大相似之处

d289d440b13ccf5d3f74562f84cd6c79.pngfigure 5.jpeg

上面所说的共享变量,具体则是指实例变量、静态变量以及数组中的元素,但不包括局部变量、方法参数。因为后者(局部变量、方法参数)是线程私有的,自然不会被共享。需要注意的是,Java内存模型只是是一个抽象的概念,其中主内存一般对应于计算机硬件的Ram,而工作内存则不真实存在,其可能会对应于CPU寄存器、缓存或Ram。同时这里希望大家不要将JMM中的主内存、工作内存与JVM Java虚拟机中的堆、栈、方法区等Java内存区域相混淆,因为二者不是在一个层次上的内存划分,这里JMM是为Java并发而服务的

并发编程的三个特性

Java内存模型就是围绕着在并发过程中如何处理原子性、可见性、有序性这三个特性来建立的,其通过相关的规范、规则来避免并发编程可能出现的线程安全问题

Atomicity 原子性

原子性是指一个或多个操作是不可中断的,要么全部执行,要么全部不执行,不存在只执行其中一部分的情况。在JMM中定义了以下八种操作来完成共享变量在主内存与工作内存之间的具体交互。与此同时,下面提及的每一种操作均由JMM来直接保证其具备原子性,所以Java虚拟机实现时必须要满足下列操作的原子性

  1. lock(锁定) :作用于主内存的变量,它把一个变量标示为一条线程独占的状态
  2. unlock(解锁) :作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
  3. read(读取) :作用于主内存的变量,它把一个变量的值从主内存传输到线程内的工作内存中,以便随后的load操作使用
  4. load(载入) :作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
  5. use(使用) :作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行此操作
  6. assign(赋值) :作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行此操作
  7. store(存储) :作用于工作内存的变量,它把工作内存中一个变量的值传递到主内存中,以便随后的write操作使用
  8. write(写入) :作用于主内存的变量,它把store操作从工作内存中得到的变量值放入主内存的变量中

在开发中通常需要保证多个操作的原子性,所以在JMM中提供了lock、unlock操作,尽管虚拟机未将这两个操作开放提供给用户使用。但是却提供了更高层次的字节码指令monitorenter、monitorexit来隐式地使用了这两个操作,而这两个字节码指令反映到Java代码层面就是同步块——synchronized关键字。所以synchronized块之间的一系列操作同样具备原子性

Note

值得一提的是,对于long、double类型变量而言,JMM并不强制要求虚拟机在实现时保证read、load、store、write操作的原子性,即所谓的long、double的非原子性协定。不过就实际开发而言,我们也无需过多担心这点。因为目前大多数商用虚拟机几乎都会选择实现long、double数据读写操作的原子性

Visibility 可见性

可见性则是当一个线程修改了共享变量的值,其他线程能够立即感知到这个修改。前面我们已经提到JMM中各线程的工作内存相互是不可见的,即不可以直接访问其他线程的工作内存。所以在JMM中可见性是通过主内存作为传递媒介来实现的,即线程在修改了共享变量的值后需要同步回主内存,在线程读取时从主内存拷贝副本

Ordering 有序性

重排序

一般大家会认为程序的执行是按我们程序编码时的顺序关系顺序执行,但实际上并不是这样。现代CPU会利用一些诸如多级流水线(多条指令可重叠执行)等并行技术来提高执行效率。CPU可以将多条指令打乱来重新组织执行顺序,而不按程序编码时的顺序进行执行,即CPU的乱序执行(out-of-order execution,OOE)。与此同时,编译器在很多情况下(例如优化等)也会对指令执行顺序进行调整。基于此,不论是编译器还是处理器CPU都会对程序指令进行重排序。通过下面这个示例即可观察到重排序这一现象

public class Ordering {
    public static int x = 0;
    public static int y = 0;

    public static void test1() throws Exception {

        HashSet resultSet = new HashSet<>();for( long i=0; i500000*100); i++ ) {
            x = 0;
            y = 0;
            Map map = new ConcurrentHashMap<>();
            Thread threadA = new Thread(() ->
            {int a = y;  // ①
                x = 1;      // ②
                map.put("a", a);
            });
            Thread threadB = new Thread(() ->
            {int b = x;   // ③
                y = 1;      // ④
                map.put("b", b);
            });
            threadA.start();
            threadB.start();
            threadA.join();
            threadB.join();
            String result = " { a=" + map.get("a") + ", b=" + map.get("b") + " } ";
            resultSet.add(result);
        }
        System.out.println(resultSet);
    }
}

从下面执行结果中红框部分,我们可以看到竟然出现a=1,b=1的执行结果,其可以说明在程序的执行顺序中 ②比③先执行、④比①先执行。而要满足上述的执行顺序,要么是因为②比①先执行,要么是因为④比③先执行。即程序指令发生了重排序

5c686a04ef00df071ca61d37329d366d.pngfigure 6.png

As-If Serial 语义

As-If Serial 语义,是指无论做怎样的重排序单线程的执行结果都不应被改变。即在本线程内进行观察,程序的执行是有序的而没有乱序执行,看上去是串行的。考虑下面的例子,下面3行代码的顺序是 ①->②->③,但是由于①与②之间不存在任何数据依赖关系,所以编译器、处理器可以对①、②操作进行重排序。即实际的执行顺序可能是 ②->①->③,虽然对指令进行了重排序,但并不影响最终的结果

double pi = 3.14159;   // ①
double r = 2.0;     // ②
double s = pi * r * r;  // ③

所以说,遵守As-If Serial语义的编译器、Runtime和硬件(CPU等)共同把单线程程序保护了起来,即在程序中不应能够观察到重排序的效果。其为开发单线程程序的开发者创建了一个幻觉,即单线程程序是按程序编码的顺序来执行的。Java内存模型在单线程中的有序性可由As-If Serial语义提供保证

Happens-Before 先行发生原则

在Java的多线程程序中,如果在一个线程中观察另外一个线程,则可以发现其所有的操作都是无序的。其原因在于指令的重排序、工作内存与主内存同步延迟。为此Java提供了volatile、synchronized两个关键字来保证线程间操作的有序性。而如果在Java内存模型中所有的有序性都仅仅依靠volatile、synchronized来实现的话,那么就会导致我们在实际开发多线程程序时非常繁琐。为此Java内存模型中提出了一个 Happens-Before 先行发生原则,其定义了两项操作之间的偏序关系。当A操作先行发生于操作B,其含义是在发生B操作之前,A操作产生的影响(包括但不限于修改共享变量的值、发送消息、调用方法)能够被B操作观察到

程序顺序规则 :在一个线程内,按照分支、循环等控制流等顺序,编写在前面的操作先行发生于书写在后面的操作 监视器锁规则 :一个unlock操作先行发生于后面对同一个锁的lock操作。这里的后面是指令在执行时间上的先后顺序 volatile变量规则 :对一个volatile变量的写操作先行发生于后面对这个变量的读操作。这里的后面是指令在执行时间上的先后顺序 线程启动规则 :Thread对象的start()方法先行发生于此线程的每一个动作 线程终止规则 :线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行 线程中断规则 :对线程interrupted()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生 对象终结规则 :一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始 传递性 :如果操作A先行发生于操作B、操作B先行发生于操作C,那么可以得出操作A先行发生于操作C的结论

在JMM中,这些原则无需任何其他同步手段协助就已经存在。故在实际的开发过程中,Happens-Before 先行发生原则是我们判断数据竞争、线程安全的主要依据,可以在编码中直接应用。如果两个操作之间的关系不在上述原则之列且无法从上述原则中推导出来,那么就无法保证他们的执行顺序,即发生重排序

当然值得一提的是,Happens-Before原则实际上是对Java内存模型的一种近似性描述,不够严谨,但是可以方便我们日常开发应用参考。例如在一个线程中存在如下代码

double pi = 3.14159;   // ①
double r = 2.0;     // ②
double s = pi * r * r;  // ③

根据程序顺序原则,我们可以得到下面的三个偏序关系:

  • ①先行于③发生
  • ②先行于③发生
  • ①先行于②发生

前2个偏序关系显然是必要的,但是对于第3个偏序关系则不是必要的。也就是说①、②发生重排序,②先行于①发生,并不会改变程序的执行结果。故如果Happens-Before所禁止的重排序并不会改变程序的执行结果,JMM将不会要求编译器、处理器来禁止该重排序。即在此种条件下JMM允许进行重排序。这样做的目的也是显然易见的,即最大程度减少对编译器、处理器优化的限制

Memory Barrier 内存屏障

JMM向上给开发者提供了一些规则来保证并发编程时的一定有序性,向下则是通过编译器在适当位置插入相关Memory Barrier 内存屏障指令禁止特定类型的重排序来实现相关操作的有序。Memory Barrier 内存屏障,又称作Memory Fence内存栅栏,其是对一类CPU指令的统称。其作用在于保证CPU执行相关操作时一定的有序,避免CPU对相关指令的乱序执行。具体的,JMM将内存屏障指令分为以下四种类型

  1. LoadLoad屏障 :在指令序列 Load1; LoadLoad; Load2 中,该类型屏障确保Load1数据的装载先于Load2及其后所有装载指令的的操作
  2. StoreStore屏障 :在指令序列 Store1; StoreStore; Store2 中,该类型屏障确保Store1数据的内存写入(使其对其他处理器可见)先于Store2及其后所有存储指令的操作
  3. LoadStore屏障 :在指令序列 Load1; LoadStore; Store2 中,该类型屏障确保Load1数据的装载先于Store2及其后所有存储指令的操作
  4. StoreLoad屏障 :在指令序列 Store1; StoreLoad; Load2 中,该类型屏障确保Store1数据的内存写入(使其对其他处理器可见)先于Load2及其后所有装载指令的操作。在大多数处理器的实现中该类型屏障由于同时具备其他三个类型屏障的效果,所以其是一个万能屏障。当然该屏障开销也是最大的

参考文献

  1. Java并发编程之美 翟陆续、薛宾田著
  2. 深入理解Java虚拟机·第2版 周志明著
  3. JSR-133: Java Memory Model and Thread Specification

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/271447.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑维修知识:电脑常见故障维修大全及解决方法

电脑已经成为我们学习生活娱乐必不可少的设备了&#xff0c;用得时间久了难免会遇到小故障&#xff0c;今天我们一起来看下遇到常见的电脑方面的小故障&#xff0c;我们应该如何去自己检测和维修吧。电脑检测故障我们还是要从电脑的几大硬件开始检查起。1、CPU打开机箱查看CPU风…

工程图样中粗实线的用途_图纸天天画,粗实线和细实线的线宽比例是多少?2:1还是3:1?...

点击上方头条号“机械设计一点通”关注我们&#xff0c;每天学习一个机械设计相关知识点我们知道&#xff1a;机械制图中为了表示不同内容&#xff0c;并能分清主次&#xff0c;必须使用不同线型。图线的线型由线宽和线素长度等构成&#xff0c;机械制图中各种线型都有相应宽度…

STM32F4_USART配置及细节描述

Ⅰ、概述 关于USART串口通信&#xff0c;可以说是MCU的标配。不管是在实际项目应用中&#xff0c;还是在开发过程中&#xff0c;它都起着很重要的作用。 在项目应用中我们常常使用UART串口进行通信&#xff0c;根据通信的距离及稳定性&#xff0c;还选择添加RS232、RS485等对UA…

腾讯面试:SaaS多租户,如何设计?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业网易、美团、字节、如阿里、滴滴、极兔、有赞、希音、百度、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 多租户设计&#xff0c;如何 技术选型&#xff…

Mac中Finder是什么?怎么打开?

很多人都知道windows系统中的资源管理器&#xff0c;不过不知道什么是finder。finder和资源管理器一样&#xff0c;都是用来管理文件&#xff0c;finder存在于mac统中&#xff0c;那么finder有什么作用呢?下面下班就为大家分享关于mac系统中finder的相关内容。   1、怎么打开…

phpstudy页面不存在_网站的404页面对于SEO的重要作用

随着网站建设的需求和要求越来越多&#xff0c;网站的新形式也逐渐成为人们改版的方向&#xff0c;但是在网站的改版中难免会出现一些小差错&#xff0c;导致网站的运行不顺畅&#xff0c;这很有可能就是网站建设中忘记设计404页面&#xff0c;那么4040页面能给网站带来哪些好处…

计算机系统基础:虚拟存储管理知识笔记

1、虚拟存储管理概念 一个计算机任务只需要部分装入主存便可以启动运行&#xff0c;其余部分留在磁盘上&#xff0c;在需要的时候装入主存&#xff0c;这样可以提高主存空间的利用率。这样该系统所具有的主存容量会比实际主存容量大很多&#xff0c;这样的存储器称为虚拟存储器…

git推送指令配置_git 常用命令

git 简介在实际开发中&#xff0c;会使用git作为版本控制工具来完成团队协作。因此&#xff0c;对基本的git操作指令进行总结是十分有必要的&#xff0c;本文对一些术语或者理论基础&#xff0c;不重新码字&#xff0c;可以参考廖雪峰老师的博文&#xff0c;本文只对命令做归纳…

传统的线性降维方法效果不佳。_机器学习西瓜书简明笔记(11)降维与度量学习...

上篇主要介绍了几种常用的聚类算法&#xff0c;首先从距离度量与性能评估出发&#xff0c;列举了常见的距离计算公式与聚类评价指标&#xff0c;接着分别讨论了K-Means、LVQ、高斯混合聚类、密度聚类以及层次聚类算法。K-Means与LVQ都试图以类簇中心作为原型指导聚类&#xff0…

计算机系统基础:设备管理知识笔记

1、设备管理介绍 设备管理主要包括设备分配、缓冲区管理、实际物理I/O设备操作、通过管理提高设备利用率和方便用户使用的目的。 设备属于计算机系统和外界交互的工具&#xff0c;不要负责计算机和外部的输入/输出工作&#xff0c;通常称为外设。 2、设备分类 2.1 按数据组织分…

灌篮高手微信登录是什么服务器,灌篮高手微信登录版本

这款《灌篮高手》手游游戏是由同名的火爆动漫改写而成的&#xff0c;里边的游戏角色都是有极致的复原和保存&#xff0c;足球运动员特点都是有一定的展现。也有经典的动漫故事情节和每个高等院校足球队的复原。现阶段为大伙儿出示的是灌篮高手微信登录版本&#xff0c;能够和小…

华为发布岳云鹏手机_刚刚,华为发布鸿蒙2.0!手机可用!

不凡的2020年激动人心的时刻终于到来今天下午3时华为开发者大会2020在正式开幕鸿蒙2.0发布&#xff01;本次大会包含主题演讲、技术论坛、松湖对话、Codelabs、Teach.Hour、互动体验等系列环节&#xff0c;大会将持续3天&#xff0c;众多活动也将于线上同步直播。技术论坛环节在…

Mac下安装jdk8

直接点击dmg文件 安装成功 在终端输入 Java -vesion 提供百度云链接方便大家下载 链接: https://pan.baidu.com/s/1n2SY-61KFb6-c1UcshZt1Q 链接: https://pan.baidu.com/s/1n2SY-61KFb6-c1UcshZt1Q 密码: g0mj

硬件基础:嵌入式物联网系统软硬件基础知识大全

本文主要介绍嵌入式系统的基础知识&#xff0c;涉及嵌入式软件和硬件的方方面面&#xff0c;希望对各位有帮助。嵌入式系统基础1、嵌入式系统的定义&#xff08;1&#xff09;定义&#xff1a;以应用为中心&#xff0c;以计算机技术为基础&#xff0c;软硬件可裁剪&#xff0c;…

ctrl z撤销后如何恢复_回收站清空后数据如何恢复?

回收站清空后数据如何恢复&#xff1f;怎么恢复回收站误删除文件&#xff1f;很多人为了电脑的更好运行以及其它的原因&#xff0c;都会定期清理一下桌面的回收站里的文件&#xff0c;有时候会一键清空&#xff0c;可能是想全部删除又或者是想特定删除一些而不小心全清理了&…

jh锂电保护电路_锂电池过充电、过放电、过流及短路保护电路原理及电路图

下图为一个典型的锂离子电池保护电路原理图。该保护回路由两个MOSFET(V1、V2)和一个控制IC(N1)外加一些阻容元件构成。控制IC负责监测 电池电压与回路电流&#xff0c;并控制两个MOSFET的栅极&#xff0c;MOSFET在电路中起开关作用&#xff0c;分别控制着充电回路与放电回路的导…

一个串口接2个设备_重庆市有2个大观镇,一个乡村旅游发达,一个特产柚子

同名的乡镇是很常见的现象&#xff0c;就连一个市里就有很多同名的乡镇&#xff0c;在之前的文章里说过&#xff0c;重庆市有2个临江镇、2个义和镇等。今天继续看看&#xff0c;重庆市内两个同名乡镇——大观镇&#xff0c;一个属于南川区&#xff0c;一个属于梁平区&#xff0…

计算机系统基础:设备管理采用的相关技术知识笔记

1、通道技术 设备管理的通道技术是为了数据传输可以独立于CPU&#xff0c;让CPU从繁琐的I/O工作中解脱出来。设置通道后&#xff0c;CPU、只需要向通道发I/O指令,通道接收到指令后&#xff0c;从主存中取出本次要执行的通道程序并执行&#xff0c;只有完成了I/O任何后才会向CPU…

treelist自动定位行_国内首创!金川集团千米深井双定位补偿摇台投用

新甘肃客户端金昌讯(新甘肃甘肃日报记者谢晓玲)近日&#xff0c;金川集团二矿区18行副井提升系统罐笼自动化改造项目顺利完成并投入使用。项目研发的双定位补偿摇台是国内同行业首创&#xff0c;可以实现罐笼在井筒内水平和竖直方向的同步定位&#xff0c;从根本上解决了传统摇…