栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

计算机操作系统

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

计算机操作系统

  1. 查看某进程运行状态指令:ps -aux | grep PID
  2. 查看进程运行状态、查看内存使用情况的指令:top
  3. 压缩文件:tar -zcvf hhh.tar.gz hhh   //压缩hhh为hhh.tar.gz

解压文件:tar -tzvf hhh.tar.gz

  1. 查询连接数:netstat
  2. 通过进程名查占用端口:查看进程pid   ps -ef | grep 进程名   

                      通过pid查看占用端口   netstat -nap | grep 进程pid

通过端口查进程:netstat -nap | grep 端口号

  1. 线程和进程的区别:

(1)一个线程从属于一个进程; 一个进程可以包含多个线程。

(2)一个线程挂掉,对应的进程挂掉; 一个进程挂掉,不会影响其他进程。

(3)进程是系统资源调度/CPU分配资源的最小单位; 线程CPU调度的最小单位。

(4)进程系统开销显著大于线程开销; 线程需要的系统资源更少。

(5)进程在执行时拥有独立的内存单元,多个线程共享进程的堆和方法区(JDK1.8之后的元空间资源),如代码段、数据段、扩展段; 但每个线程拥有自己的程序计数器、虚拟机栈、本地方法栈。

(6)进程切换时需要刷新TLB并获取新的地址空间,然后切换硬件上下文和内核栈,线程切换时只需要切换硬件上下文和内核栈。

(7)通信方式不一样。

(8)进程适应于多核、多机分布;线程适用于多核。

(9)进程间基本是独立的,线程间不一定

  1. 操作系统定义:管理计算机硬件与软件资源的程序,操作系统存在屏蔽了硬件层的复杂性,操作系统的内核(Kernel)是操作系统的核心部分,它负责系统的内存管理,硬件设备的管理,文件系统的管理以及应用程序的管理。 内核是连接应用程序和硬件的桥梁,决定着系统的性能和稳定性。
  2. 系统调用:进程访问资源特点分为用户态进程(直接读取用户程序的数据)、系统态进程(几乎可以访问计算机的任何资源,不受限制)。凡是与系统态级别的资源有关的操作(如文件管理、进程控制、内存管理等),都必须通过系统调用方式向操作系统提出服务请求。

系统调用分为:设备管理。完成设备的请求或释放,以及设备启动等功能。

文件管理。完成文件的读、写、创建及删除等功能。

进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。

进程通信。完成进程之间的消息传递或信号传递等功能。

内存管理。完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。

  1. 进程状态:

创建状态(new) :进程正在被创建,尚未到就绪状态。

就绪状态(ready) :进程已处于准备运行状态,即进程获得了除了处理器之外的一切所需资源,一旦得到处理器资源(处理器分配的时间片)即可运行。

运行状态(running) :进程正在处理器上上运行(单核 CPU 下任意时刻只有一个进程处于运行状态)。

阻塞状态(waiting) :又称为等待状态,进程正在等待某一事件而暂停运行如等待某资源为可用或等待 IO 操作完成。即使处理器空闲,该进程也不能运行。

结束状态(terminated) :进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行。

  1. 进程间通信方式

管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。

有名管道(Names Pipes) : 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循先进先出(first in first out)。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。

信号(Signal) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;

消息队列(Message Queuing) :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显式地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列允许一个或多个进程向它写入或读取消息。

信号量(Semaphores) :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。

共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。好处:效率高。进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。

套接字(Sockets) : 此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

  1. 进程的调度算法

先到先服务(FCFS)调度算法: 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。

短作业优先(SJF)的调度算法: 从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。

时间片轮转调度算法: 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称 RR(Round robin)调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。

多级反馈队列调度算法:前面介绍的几种进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。因而它是目前被公认的一种较好的进程调度算法,UNIX 操作系统采取的便是这种调度算法。

优先级调度:为每个流程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级。

  1. 线程间的通信方式

锁机制:包括互斥锁、条件变量、读写锁互斥锁提供了以排他方式防止数据结构被并发修改的方法。读写锁允许多个线程同时读共享数据而对写操作是互斥的。条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。

信号量机制(Semaphore):包括无名线程信号量和命名线程信号量

信号机制(Sianal):类似进程间的信号处理线程间的通信目的主要是用干线程同步,所以线程没有像进程通信中的用干数据交换的通信机制。

  1. 线程同步方式

互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。

信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。

事件(Event) :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。

  1. 进程切换为什么比线程更消耗资源?

进程切换时需要刷新TLB并获取新的地址空间,然后切换硬件上下文和内核栈;

线程切换时只需要切换硬件上下文和内核栈。.

解释:进程是程序的动态表现。一个程序进行起来后,会使用很多资源,比如寄存器,内存,文件等。每当切换进程时,必须要考虑保存当前进程的状态。状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开的文件描述符的的集合,这个状态叫做上下文(Context)。想要切换进程,保存的状态很多,不仅如此,由于虚拟内存机制,进程切换时需要刷新TLB并获取新的地址空间。

线程存在于进程中,一个进程可以有一个或多个线程。线程是运行在进程上下文中的逻辑流,这个线程可以独立完成一项任务。同样线程有自己的上下文,包括唯一的整数线程ID,栈、栈指针、程序计数器、通用目的寄存器和条件码。可以理解为线程上下文是进程上下文的子集。

由于保存线程的上下文明显比进程的上下文小,因此系统切换线程时,必然开销更小。

  1. 僵尸进程和孤儿进程

正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。父进程永远无法预测子进程到底什么时候结束。当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得了进程的终止状态。

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收收养,并由init进程对它们完成状态收集工作。

僵尸进程;一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

  1. 锁:乐观锁、悲观锁、自旋锁、公平锁、非公平锁、共享锁、独占锁、锁状态(重量级锁、轻量级锁、偏向锁、无锁状态)、分段锁、死锁、Synchronized 同步锁、ReentrantLock

乐观锁:读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。(java中的乐观锁基本都是通过CAS操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败)

悲观锁:写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会 block 直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。

自旋锁:持有锁的线程能短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后立即获取锁,避免用户线程和内核的切换的消耗。线程自旋消耗cpu,因此需要设定一个自旋等待的最大时间,超过最大时间仍没有获取到锁,就停止自旋进入阻塞状态。

自旋锁特点:用于临界区互斥、在任何时刻最多只能有一个执行单元获得锁、要求持有锁的处理器所占用的时间尽可能短、等待锁的线程进入忙循环。

自旋锁存在的问题:如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高。

无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。

自旋锁优点:不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换。 执行速度快。

自旋锁与互斥锁的区别:自旋锁与互斥锁都是为了实现保护资源共享的机制。

无论是自旋锁还是互斥锁,在任意时刻,都最多只能有一个保持者。

获取互斥锁的线程,如果锁已经被占用,则该线程将进入睡眠状态;获取自旋锁的线程则不会睡眠,而是一直循环等待锁释放。

公平锁:锁的分配机制是公平的,通常先对锁提出获取请求的线程会先被分配到锁,ReentrantLock 在构造函数中提供了是否公平锁的初始化方式来定义公平锁。

非公平锁:JVM按随机、就近原则分配锁的机制则称为非公平锁,多个线程竞争锁资源,抢占锁的所有权。ReentrantLock在构造函数中提供了是否公平锁的初始化方式,默认为非公平锁。非公平锁实际执行效率远远超出公平锁,除非有特殊需要,不然一般都是非公平锁。 Java 中的 synchronized 也是非公平锁。

共享锁:允许多个线程同时获取锁,并发访问共享资源,如:ReadWriteLock。共享锁是一种乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。

独占锁:每次只能有一个线程能持有锁, ReentrantLock 就是以独占方式实现的互斥锁。独占锁是一种悲观保守的加锁策略,避免了读/读冲突,如果某个只读线程获取锁,则其他读线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。

锁升级:锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的, 也就是说只能从低到高升级,不会出现锁的降级)锁状态:无锁状态、偏向锁、轻量级锁和重量级锁。

重量级锁:依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。 Synchronized 是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态,成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因。JDK1.6之后引入了轻量级锁和偏向锁。

轻量级锁:“轻量级”是相对于使用操作系统互斥量来实现的传统锁而言的。但是,轻量级锁并不是用来代替重量级锁的,本意是在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗。轻量级锁所适应的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。

偏向锁:研究发现大多数情况下锁不仅不存在多线程竞争,而且总是由同一线程多次获得。偏向锁的目的是在某个线程获得锁之后,消除这个线程锁重入(CAS)的开销,看起来让这个线程得到了偏护。为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次 CAS 原子指令,而偏向锁只需要在置换ThreadID 的时候依赖一次 CAS 原子指令(由于一旦出现多线程竞争的情况就必须撤销偏向锁,所以偏向锁的撤销操作 的性能损耗必须小于节省下来的 CAS 原子指令的性能消耗)。偏向锁是在只有一个线程执行同步块时进一步提高性能。

分段锁:并非一种实际的锁,而是一种思想ConcurrentHashMap是学习分段锁的最好实践。

死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。

  1. 产生死锁的条件

互斥:资源必须处于非共享模式,即一次只有一个进程可以使用。如果另一进程申请该资源,那么必须等待直到该资源被释放为止。

占有并等待:一个进程至少应该占有一个资源,并等待另一资源,而该资源被其他进程所占有。

非抢占:资源不能被抢占。只能在持有资源的进程完成任务后,该资源才会被释放。

循环等待:有一组等待进程 {P0, P1,..., Pn}, P0 等待的资源被 P1 占有,P1 等待的资源被 P2 占有,......,Pn-1 等待的资源被 Pn 占有,Pn 等待的资源被 P0 占有。

  1. 解决死锁办法:预防、避免、检测、解除

预防是采用某种策略,限制并发进程对资源的请求,从而使得死锁的必要条件在系统执行的任何时间上都不满足。

避免则是系统在分配资源时,根据资源的使用情况提前做出预测,从而避免死锁的发生

检测是指系统设有专门的机构,当死锁发生时,该机构能够检测死锁的发生,并精确地确定与死锁有关的进程和资源。

解除 是与检测相配套的一种措施,用于将进程从死锁状态下解脱出来。

  1. 死锁预防:静态分配策略(破坏占有并等待)进程要么占有所有的资源然后开始执行,要么不占有资源,不会出现占有一些资源等待一些资源的情况。

层次分配策略(破坏循环等待):所有的资源被分成了多个层次,一个进程得到某一次的一个资源后,它只能再申请较高一层的资源;当一个进程要释放某层的一个资源时,必须先释放所占用的较高层的资源,按这种策略,是不可能出现循环等待链的,因为那样的话,就出现了已经申请了较高层的资源,反而去申请了较低层的资源,不符合层次分配策略

  1. Synchronized 同步锁(对象锁、类锁)

synchronized可以把任意一个非 NULL 的对象当作锁。属于独占式的悲观锁,同时属于可重入锁。

应用Sychronized关键字时需要把握如下注意点:

一把锁只能同时被一个线程获取,没有获取到锁的线程只能等待。

每个实例都有对应自己的一把锁(this),不同实例之间互不影响;例外:锁对象是*.class以及synchronized修饰的是static方法的时候,所有对象公用同一把锁。

synchronized修饰的方法,无论方法正常执行完毕还是抛出异常,都会释放锁。

Synchronized 作用范围:可以修饰静态方法,不能修饰静态代码块。

对象锁:包括方法锁(默认锁对象是this,当前实例对象)和同步代码块锁(自己指定锁对象)

方法锁:synchronized修饰普通方法,锁对象默认为this,当前实例。

类锁:指synchronize修饰静态的方法或指定锁对象为Class对象。所有线程需要的锁都是同一把。修饰静态方法时,监视器锁(monitor)是对象的Class实例,Class数据存储在永久代,静态方法锁相当于类的全局锁。

Synchronized本质上是通过什么保证线程安全的? 加锁和释放锁的原理、可重入(可重新进入)原理、保证可见性原理。

保证可见性原理:内存模型和happens-before规则:即监视器锁规则,对同一个监视器的解锁,happens-before于对该监视器的加锁。

如果A happens-before B,则A的执行结果对B可见,并且A的执行顺序先于B。线程A先对共享变量A进行加一,由A happens-beforeB关系可知线程A的执行结果对线程B可见。

Synchronized的底层实现原理:

(1)synchronized作用在代码块时,它的底层是通过monitorenter、monitorexit指令来实现的。

monitorenter:

每个对象都是一个监视器锁(monitor),当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者,如果线程已经占有该monitor只是重新进入,则进入monitor的进入数加1。如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

monitorexit:

执行monitorexit的线程必须是objectref所对应的monitor持有者,指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个monitor的所有权。

monitorexit指令出现了两次,第1次为同步正常退出释放锁,第2次为发生异步退出释放锁。

(2)synchronized作用在方法时,同步并没有通过 monitorenter 和 monitorexit 指令来完成,不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。JVM就是根据该标示符来实现方法的同步的。

当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。

(3)总结

两种同步方式本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。两个指令的执行是JVM通过调用操作系统的互斥原语mutex来实现,被阻塞的线程会被挂起、等待重新调度,会导致“用户态和内核态”两个态之间来回切换,对性能有较大影响。

Synchronized 核心组件

1) Wait Set:哪些调用 wait 方法被阻塞的线程被放置在这里;

2) Contention List: 竞争队列,所有请求锁的线程首先被放在这个竞争队列中;

3) Entry List: Contention List 中那些有资格成为候选资源的线程被移动到 Entry List 中; 4) OnDeck:任意时刻, 最多只有一个线程正在竞争锁资源,该线程被成为 OnDeck;

5) Owner:当前已经获取到所资源的线程被称为 Owner;

6) !Owner:当前释放锁的线程

Synchronized 实现

(1)JVM 每次从队列的尾部取出一个数据用于锁竞争候选者(OnDeck),但是并发情况下, ContentionList 会被大量的并发线程进行 CAS 访问,为了降低对尾部元素的竞争, JVM 会将 一部分线程移动到 EntryList 中作为候选竞争线程。

(2)Owner 线程会在 unlock 时,将 ContentionList 中的部分线程迁移到 EntryList 中,并指定 EntryList 中的某个线程为 OnDeck 线程(一般是最先进去的那个线程)。

(3)Owner 线程并不直接把锁传递给 OnDeck 线程,而是把锁竞争的权利交给 OnDeck, OnDeck 需要重新竞争锁。这样虽然牺牲了一些公平性,但是能极大的提升系统的吞吐量,在 JVM 中,也把这种选择行为称之为“竞争切换”。

(4)OnDeck 线程获取到锁资源后会变为 Owner 线程,而没有得到锁资源的仍然停留在 EntryList 中。如果 Owner 线程被 wait 方法阻塞,则转移到 WaitSet 队列中,直到某个时刻通过 notify 或者 notifyAll 唤醒,会重新进去 EntryList 中。

(5)处于 ContentionList、 EntryList、 WaitSet 中的线程都处于阻塞状态,该阻塞是由操作系统 来完成的(Linux 内核下采用 pthread_mutex_lock 内核函数实现的)。

(6)Synchronized 是非公平锁。 Synchronized 在线程进入 ContentionList 时, 等待的线程会先尝试自旋获取锁,如果获取不到就进入 ContentionList,这明显对于已经进入队列的线程是不公平的,还有一个不公平的事情就是自旋获取锁的线程还可能直接抢占 OnDeck 线程的锁资源。

(7)每个对象都有个monitor对象,加锁就是在竞争 monitor 对象,代码块加锁是在前后分别加上monitorenter和monitorexit指令来实现的,方法加锁是通过一个标记位来判断的。 (8)synchronized 是一个重量级操作,需要调用操作系统相关接口,性能是低效的,有可能给线程加锁消耗的时间比有用操作消耗的时间更多。

(9)Java1.6,synchronized 进行了很多的优化, 有适应自旋、锁消除、锁粗化、轻量级锁及偏向锁等,效率有了本质上的提高。在之后推出的 Java1.7 与 1.8 中,均对该关键字的实现机理做了优化。引入了偏向锁和轻量级锁。都是在对象头中有标记位,不需要经过操作系统加锁。

(10)锁可以从偏向锁升级到轻量级锁,再升级到重量级锁。这种升级过程叫做锁膨胀;

(11)JDK 1.6 中默认是开启偏向锁和轻量级锁,可以通过-XX:-UseBiasedLocking 来禁用偏向锁。

  1. ReentrantLock

ReentantLock 继承接口 Lock 并实现了接口中定义的方法, 他是一种可重入锁,除了能完成synchronized所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。

Lock接口的主要方法:

void lock(): 执行此方法时, 如果锁处于空闲状态, 当前线程将获取到锁. 相反, 如果锁已经被其他线程持有, 将禁用当前线程, 直到当前线程获取到锁。

boolean tryLock():如果锁可用, 则获取锁, 并立即返回true, 否则返回false. 该方法和 lock()的区别在于, tryLock()只是"试图"获取锁, 如果锁不可用, 不会导致当前线程被禁用, 当前线程仍然继续往下执行代码. 而 lock()方法则是一定要获取到锁, 如果锁不可用, 就一直等待, 在未获得锁之前,当前线程并不继续向下执行。

boolean tryLock(long timeout TimeUnit unit): 如果锁在给定等待时间内没有被另一个线程保持,则获取该锁。

lockInterruptibly():如果当前线程未被中断,获取锁。

lock 和 lockInterruptibly,如果两个线程分别执行这两个方法,但此时中断这两个线程, lock 不会抛出异常,而 lockInterruptibly 会抛出异常。

void unlock():执行此方法时, 当前线程将释放持有的锁. 锁只能由持有者释放, 如果线程并不持有锁, 却执行该方法, 可能导致异常的发生。

Condition newCondition():条件对象,获取等待通知组件。该组件和当前的锁绑定,当前线程只有获取了锁,才能调用该组件的await()方法,而调用后,当前线程将缩放锁。 

getHoldCount():查询当前线程保持此锁的次数,也就是执行此线程执行lock方法的次数。

getQueueLength():返回正等待获取此锁的线程估计数,比如启动10个线程,1个 线程获得锁,此时返回的是9。

getWaitQueueLength:(Condition condition)返回等待与此锁相关的给定条件的线程估计数。比如10个线程,用同一个condition对象,并且此时这10个线程都执行了condition 对象的await方法,那么此时执行此方法返回10 。

hasWaiters(Condition condition):查询是否有线程等待与此锁有关的给定条件 (condition),对于指定contidion对象,有多少线程执行了condition.await方法。

hasQueuedThread(Thread thread):查询给定线程是否等待获取此锁。

hasQueuedThreads():是否有线程等待此锁。

isFair():该锁是否公平锁。

isHeldByCurrentThread():当前线程是否保持锁锁定,线程的执行 lock 方法的前后分 别是false和true。

isLock():此锁是否有任意线程占用。

  1. Synchronized与Lock的区别

(1)synchronized是Java关键字,在JVM层面实现加锁和解锁;Lock是一个接口,在代码层面实现加锁和解锁

(2)synchronized可以用在代码块上、方法上;Lock只能写在代码里。

(3)synchronized在代码执行完或出现异常时自动释放锁;Lock不会自动释放锁,需要在finally中显示释放锁。

(4)synchronized会导致线程拿不到锁一直等待;Lock可以设置获取锁失败的超时时间。

(5)synchronized无法得知是否获取锁成功;Lock可以通过tryLock得知加锁是否成功。

(6)synchronized锁可重入、不可中断、非公平;Lock锁可重入、可中断、可公平/不公平,并可以细分读写锁以提高效率。

  1. CAS在什么地方用到过吗?

CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。

高并发环境下,对同一个数据的并发读(两边都读出余额是100)与并发写(一个写回28,一个写回38)导致的数据一致性问题。

解决方案是在set写回的时候,加上初始状态的条件compare,只有初始状态不变时,才允许set写回成功,这是一种常见的降低读写锁冲中突,保证数据一致性的方法。

  1. 操作系统内存管理:主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情
  2. 内存管理机制

连续分配管理方式:为一个用户程序分配一个连续的内存空间,常见的如块式管理。

非连续分配管理方式:允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理、段式管理、段页式管理。

块式管理:将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片。

页式管理 :把主存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。

段式管理:页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。段式管理把主存分为一段段的,段是有实际意义的,每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址。

页是物理单位,段是逻辑单位。分页可以有效提高内存利用率,分段可以更好满足用户需求。

段页式管理机制 。段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。

  1. 虚拟内存

虚拟内存 可以让程序可以拥有超过系统物理内存大小的可用内存空间。虚拟内存为每个进程提供了一个一致的、私有的地址空间,让每个进程产生了一种自己在独享主存的错觉(每个进程拥有一片连续完整的内存空间)。更加有效地管理内存并减少出错。重要意义是它定义了一个连续的虚拟地址空间,并且 把内存扩展到硬盘空间。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/939762.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号