当前位置:首页 » 资源管理 » 锁消耗的是什么资源
扩展阅读

锁消耗的是什么资源

发布时间: 2022-07-09 14:10:16

㈠ java多线程,对象锁是什么概念

java线程:

1.线程中一些基本术语和概念

1.1线程的几个状态
初始化状态
就绪状态
运行状态
阻塞状态
终止状态
1.2 Daemon线程
Daemon线程区别一般线程之处是:主程序一旦结束,Daemon线程就会结束。
1.3锁的定义
为了协调多个并发运行的线程使用共享资源才引入了锁的概念。
1.4死锁
任何多线程应用程序都有死锁风险。当一组线程中的每一个都在等待一个只
有该组中另一个线程才能引起的事件时,我们就说这组线程死锁了。换一个说法
就是一组线程中的每一个成员都在等待别的成员占有的资源时候,就可以说这组
线程进入了死锁。死锁的最简单情形是:线程 A 持有对象 X 的独占锁,并且
在等待对象 Y 的锁,而线程 B 持有对象 Y 的独占锁,却在等待对象 X 的锁。
除非有某种方法来打破对锁的等待(Java 锁定不支持这种方法),否则死锁的线
程将永远等下去。

1.5.Java对象关于锁的几个方法
1.5.1 wait方法
wait方法是java根对象Object含有的方法,表示等待获取某个锁。在wait方法进入前,会释放相应的锁,在wait方法返回时,会再次获得某个锁。
如果wait()方法不带有参数,那只有当持有该对象锁的其他线程调用了notify或者notifyAll方法,才有可能再次获得该对象的锁。
如果wait()方法带有参数,比如:wait(10),那当持有该对象锁的其他线程调用了notify或者notifyAll方法,或者指定时间已经过去了,才有可能再次获得该对象的锁。
参考 thread.lock.SleepAndWait
1.5.2 notify/notifyAll方法
这里我就不再说明了。哈哈,偷点懒。
1.5.3 yield方法
yield()会自动放弃CPU,有时比sleep更能提升性能。
1.6锁对象(实例方法的锁)
在同步代码块中使用锁的时候,担当锁的对象可以是这个代码所在对象本身或者一个单独的对象担任,但是一定要确保锁对象不能为空。如果对一个null对象加锁,会产生异常的。原则上不要选择一个可能在锁的作用域中会改变值的实例变量作为锁对象。
锁对象,一种是对象自己担任,一种是定义一个普通的对象作为private property来担任,另外一种是建立一个新的类,然后用该类的实例来担任。
参考 :
thread.lock.UseSelfAsLock,使用对象自己做锁对象
thread.lock.UseObjAsLock 使用一个实例对象作锁对象
thread.lock.UseAFinalObjAsLock使用常量对象作为一个锁对象
1.7类锁
实例方法存在同步的问题,同样,类方法也存在需要同步的情形。一般类方法的类锁是一个static object来担任的。当然也可以采用类本身的类对象来作为类锁。
一个类的实例方法可以获得该类实例锁,还可以尝试去访问类方法,包含类同步方法,去获得类锁。
一个类的类方法,可以尝试获得类锁,但是不可以尝试直接获得实例锁。需要先生成一个实例,然后在申请获得这个实例的实例锁。
参考
thread.lock.UseStaticObjAsStaticLock 使用类的属性对象作为类锁。
thread.lock.UseClassAsStaticLock使用类的类对象作为类锁

1.8.线程安全方法与线程不安全方法
如果一个对象的所有的public方法都是同步方法,也就是说是public方法是线程安全的,那该对象的private方法,在不考虑继承的情况下,可以设置为不是线程安全的方法。
参考 thread.lock.SynMethrodAndNotSynMethrod

1.9类锁和实例锁混合使用
在实例方法中混合使用类锁和实例锁;可以根据前面说的那样使用实例锁和类锁。
在类方法中混合使用类锁和实例锁,可以根据前面说的那样使用类锁,为了使用实例锁,先得生成一个实例,然后实例锁。
参考 thread.lock.StaticLockAndObjLock
1.10锁的粒度问题。
为了解决对象锁的粒度过粗,会导死锁出现的可能性加大,锁的粒度过细,会程序开发维护的工作加大。对于锁的粒度大小,这完全要根据实际开发需要来考虑,很难有一个统一的标准。

1.11.读写锁
一个读写锁支持多个线程同时访问一个对象,但是在同一时刻只有一个线程可以修改此对象,并且在访问进行时不能修改。
有2种调度策略,一种是读锁优先,另外就是写锁优先。
参考 thread.lock.ReadWriteLock
1.12 volatile
在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步。这在JVM 1.2之前,Java的内存模型实现总是从主存读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变得非常重要。在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。

2.线程之间的通讯
在其他语言中,线程之间可以通过消息队列,共享内存,管道等方式来实现
线程之间的通讯,但是java中可以不采用这样方式,关注的是线程之间的同步。
只要保证相关方法运行的线程安全,信息共享是自然就可以显现了。
2.1屏障
屏障就是这样的一个等待点: 一组线程在这一点被同步,这些线程合并各自的结果或者运行到整体任务的下一阶段。
参考:
thread.lock. BarrierUseExample
thread.lock.Barrier
2.2.锁工具类
提供对线程锁的获取,释放功能。展示了锁的获取释放过程。可以作为一个工具类来使用。
参考:thread.lock. BusyFlag

2.3.条件变量
条件变量是POSIX线程模型提供的一种同步类型,和java中的等待通知机制类似。
虽然java中已经有了等待通知机制,但是为了减少在notify/notifyAll方法中
线程调度的开销,把一些不需要激活的线程屏蔽出去,引入了条件变量。
Java中2个(多个)条件变量可以是同一个互斥体(锁对象)。
参考:thread.lock.CondVar 条件变量类
常见的应用情形:
一个锁控制多个信号通道(例如:多个变量),虽然可以采用简单java等待通知机制,但是线程调度效率不高,而且线程可读性也不是太好,这时候可以采用创建一个锁对象(BusyFlag实例),同时使用这个BusyFlag实例来创建多个条件变量(CondVar 实例)。
经常使用到CondVar类的地方是缓冲区管理,比如:管道操作之类的。先创建一个BusyFlag实例,然后创建CondVar 实例,用这个条件变量描述缓冲区是否为空,另外创建CondVar 实例作条件变量述缓冲区是否满。
现实中,马路的红绿灯,就可以采用条件变量来描述。

3. Java线程调度
3.1 Java优先级
java的优先级别共有10种,加上虚拟机自己使用的优先级别=0这种,总共11种。
大多数情况来说,java线程的优先级设置越高(最高=10),那线程越优先运行。
3.2. 绿色线程
线程运行在虚拟机内,操作系统根本不知道这类线程的存在。
线程是由虚拟机调度的。
3.3 本地线程
线程是由运行虚拟机的操作系统完成的。
3.4 Windows本地线程
操作系统,完全能够看得到虚拟机内的每一个线程,同时虚拟机的线程和操作系统的线程是一一对应的。Java的线程调度室由操作系统底层线程决定的。
在win32平台下,windows线程只有6个优先级别。和java线程优先级别对应如下:
Java线程优先级 Windows 95/nt/2000线程优先级
0 THREAD_ PRIORITY_IDLE
1(Thread.MIN_PRIORITY) THREAD_ PRIORITY_LOWEST
2 THREAD_ PRIORITY_LOWEST
3 THREAD_ PRIORITY_BELOW_NORMAL
4 THREAD_ PRIORITY_BELOW_NORMAL
5 (Thread.NORM_PRIORITY) THREAD_ PRIORITY _NORMAL
6 THREAD_ PRIORITY _ABOVE_NORMAL
7 THREAD_ PRIORITY _ABOVE_NORMA
8 THREAD_ PRIORITY _HIGHEST
9 THREAD_ PRIORITY _HIGHEST
10 (Thread.MAX_PRIORITY) THREAD_ PRIORITY _CRITICAL

3.5线程优先级倒置与继承
如果一个线程持有锁(假设该线程名字=ThreadA,优先级别=5),另外一个线程(假设该线程名字=ThreadB,优先级别=7),现在该线程(ThreadA)处于运行状态,但是线程ThreadB申请需要持有ThreadA所获得的锁,这时候,为了避免死锁,线程A提高其运行的优先级别(提高到ThreadB的优先级别=7),而线程ThreadB为了等待获得锁,降低线程优先级别(降低到ThreadA原来的优先级别=5).
上述的这种情况,对于ThreadA,继承了ThreadB的优先级别,这成为优先级别的继承;对于ThreadB暂时降低了优先级别,成为优先级别的倒置。
当然,一旦线程ThreadA持有的锁释放了,其优先级别也会回到原来的优先级别(优先级别=5)。线程ThreadB获得了相应的锁,那优先级别也会恢复到与原来的值(优先级别=7)。

3.6循环调度
具有同样优先级的线程相互抢占成为循环调度。

4.线程池
创建一个线程也是需要一定代价的,为了降低这个代价,采用了和普通对象池的思想建立线程池,以供系统使用。
线程消耗包括内存和其它系统资源在内的大量资源。除了 Thread 对象所需的内存之外,每个线程都需要两个可能很大的执行调用堆栈。除此以外,JVM 可能会为每个 Java 线程创建一个本机线程,这些本机线程将消耗额外的系统资源。最后,虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性能。
使用线程池的方式是,先建立对象池,然后申请使用线程,程序线程运行,运行完毕,把线程返回线程池。
使用线程池的风险:同步错误和死锁,与池有关的死锁、资源不足和线程泄漏。
大家有空可以研究一下tomcat的线程池实现原理思想。
实际上是tomcat已经在从线程池的使用线程时候加上了事件处理机制。
个人认为,线程池之类的实现,一般不要自己实现,因为自己实现主要是稳定性等方面可能作的不够好。
可以参考 apache的jakarta-tomcat-5.5.6的相关代码,具体是:
jakarta-tomcat-connectors\util\java\org\apache\tomcat\util\threads的相关代码

5工作队列
使用工作队列的好处是不象直接使用线程池那样,当线城池中没有线程可以使用的时
候,使用者需要处于等待状态,不能进行其他任务的处理。
工作队列的工作原理是:
采用后台线程处理方式,客户端把任务提交给工作队列,工作队列有一组内部可以工作线程,这些工作线程从工作队列中取出任务运行,一个任务完成后,就从队列获取下一个任务进行处理。当工作队列中没有任务可以处理时候,工作线程就处于等待状态,直到获得新的任务时候,才进行新的处理。

㈡ 死循环,死递归和死锁对CPU的消耗有什么异同点

死循环,死递归和死锁对CPU的消耗基本相同,但是产生的原因是不一样的。
一、死循环。
例如在VB语言程序中,下列语句:
Do While i=1
print "*"
Loop
就是一个死循环,运行它将无休止地打印*号。
不存在一种算法,对任何一个程序及相应的输入数据,都可以判断是否会出现死循环。因此,任何编译系统都不做死循环检查。
在设计程序时,若遇到死循环,我们可以通过按下Ctrl+Pause/Break的方法,结束死循环。
然而,在编程中死循环并不是一个需要避免的问题,相反,在实际应用中,经常需要用到死循环。例如,我们使用的Windows操作系统下的窗口程序中的窗口都是通过一个叫消息循环的死循环实现的。在单片机、嵌入式编程中也经常要用到死循环。在各类编程语言中,死循环都有多种实现的方法,以C语言为例,可分别使用while.for,goto实现。
二、死锁。
两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
计算机系统中,如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。
在两个或多个任务中,如果每个任务锁定了其他任务试图锁定的资源,此时会造成这些任务永久阻塞,从而出现死锁。例如:事务A 获取了行 1 的共享锁。事务 B 获取了行 2 的共享锁。
排他锁,等待事务 B 完成并释放其对行 2 持有的共享锁之前被阻塞。
排他锁,等待事务 A 完成并释放其对行 1 持有的共享锁之前被阻塞。
事务 B 完成之后事务 A 才能完成,但是事务 B 由事务 A 阻塞。该条件也称为循环依赖关系:事务 A 依赖于事务 B,事务 B 通过对事务 A 的依赖关系关闭循环。
三、死机及其对策。
无论是死循环还是死锁,都会造成电脑死机现象。
›电脑系统在工作中,有时候会出现鼠标停滞、键盘不能输入命令等情况,这时的系统已经不能接收任何命令,这种情况被称为死机,死机可能是多种原因造成的,比如同时运行了过多的应用程序,程序的使用方法错误,电脑中某一硬件的损坏(比如硬盘或者内存)等都可能引起死机。解决的常用方法有:
同时按下键盘上的控制键加换档键加删除键,在显示的列表中单击【启动任务管理器】命令,弹出【任务管理器】对话框,单击出现问题的程序,再单击【结束任务】按钮,所选程序立即结束运行。在大多数情况下,都可以通过上述方法关闭已经失去响应的程序,并且可以继续在Windows10中操作。
如果键盘已经不能输入任何命令,可按下机箱上的复位键,几秒钟后电脑将重新启动。
如果机箱上没有复位键,可以直接按住机箱上的电源开关几秒钟,关闭电脑电源,稍后,再按机箱上的电源开关重新启动电脑即可。

㈢ 加同步锁为什么会更耗费cpu资源

处理器中一个逻辑内核只允许一个线程占用。
进程互斥,临界区都是资源保护。
比如说a,b 两个线程同时运行,它们都要存取变量var,a将var设置为20,然后继续其他工作。
这时候b也要用了,它把var设置成自己需要的值。
过一会a又回来读取var,这时候var已经不是a之前存进去的值了。

㈣ 网络流量消耗的是什么资源

流量是每秒或者一定时间设备使用的数据量,这些资源是所上的网站提供的数据等经过压缩封装等处理后传输到你的PC,手机等设备上的,算是消耗的这种资源吧。
这种资源可以说是无限的,因为大家感觉总有访问不尽的网站资源,使用不尽的网络数据。
有限的是我们手机每个月的流量(这个月一共可以用多少M),连接PC的网线、无线等的传输速度。。
仅个人理解~

㈤ 什么是死锁,怎样引入死锁

1.死锁:如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程是死锁的。
2.产生死锁的原因:
(1)竞争不可抢占性资源。
(2)竞争可消耗资源。
当系统中供多个进程共享的资源如打印机,公用队列等,其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。12

(3)进程推进顺序不当。
进程在运行过程中,请求和释放资源的顺序不当,也同样会导致产生进程死锁。12

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
一个线程也可引起死锁。12

3.产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不可抢占条件:进程已获得的资源,在末使用完之前,不能强行剥夺,只能在进程使用完时由自己释放。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。因此可以写下如下的预防死锁的方法。
4.避免死锁的方法:
(1)破坏“互斥”条件:就是在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。但一般“互斥”条件是无法破坏的。因此,在死锁预防里主要是破坏其他三个必要条件,而不去涉及破坏“互斥”条件。
(2)破坏“请求和保持”条件:在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源。
方法一:所有进程在运行之前,必须一次性地申请在整个运行过程中所需的全部资源。这样,该进程在整个运行期间,便不会再提出资源请求,从而破坏了“请求”条件。系统在分配资源时,只要有一种资源不能满足进程的要求,即使其它所需的各资源都空闲也不分配给该进程,而让该进程等待。由于该进程在等待期间未占有任何资源,于是破坏了“保持”条件。
该方法优点:简单、易行且安全。
缺点:a.资源被严重浪费,严重恶化了资源的利用率。
b.使进程经常会发生饥饿现象。12

方法二:要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R。
(3)破坏“不可抢占”条件:允许对资源实行抢夺。
方法一:如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源。
方法二:如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,该方法才能预防死锁。
(4)破坏“循环等待”条件:将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。
利用银行家算法避免死锁:
银行家算法:
设进程i提出请求Request[j],则银行家算法按如下规则进行判断。
(1) 如果Request[j]≤Need[i,j],则转向(2),否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
(2) 如果Request[j]≤Available[j],则转向(3);否则表示尚无足够资源,Pi需等待。
(3) 假设进程i的申请已获批准,于是修改系统状态:
Available[j]=Available[j]-Request[i]
Allocation[i,j]=Allocation[i,j]+Request[j]
Need[i,j]=Need[i,j]-Request[j]
(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
安全性算法:
(1) 设置两个工作向量Work=Available;Finish[i]=False
(2) 从进程集合中找到一个满足下述条件的进程,
Finish [i]=False;

Need[i,j]≤Work[j];

如找到,执行(3);否则,执行(4)123456

(3) 设进程获得资源,可顺利执行,直至完成,从而释放资源。
Work[j]=Work[j]+Allocation[i,j];

Finish[i]=True;

Go to step 2;123456

(4) 如所有的进程Finish[i]=true,则表示安全;否则系统不安全。
5.死锁的解除:
一旦检测出死锁,就应立即釆取相应的措施,以解除死锁。死锁解除的主要两种方法:
1) 抢占资源。从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以解除死锁状态。
2) 终止(或撤销)进程。终止(或撤销)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态解脱出来。
总结:
一般情况下,如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此就永远处于挂起等待状态了,这叫做死锁(Deadlock)。另⼀一种典型的死锁情形是这样:线程A获得了锁1,线程B获得了锁2,这时线程A调⽤用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调⽤用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。12

注意:
写程序时应该尽量避免同时获得多个锁,如果一定有必要这么做,则有一个原则:如果所有线程在需要多个锁时都按相同的先后顺序(常见的是按Mutex变量的地址顺序)获得锁,则不会出现死锁。比如一个程序中用到锁1、锁2、锁3,它们所对应的Mutex变量的地址是锁1<锁2<锁3,那么所有线程在需要同时获得2个或3个锁时都应该按锁1、锁2、锁3的顺序获得。如果要为所有的锁确定一个先后顺序比较困难,则应pthread_mutex_trylock调用代替pthread_mutex_lock 调用,以免死锁。

㈥ java多线程中的死锁,活锁,饥饿,无锁都是什么鬼

死锁发生在当一些进程请求其它进程占有的资源而被阻塞时。

另外一方面,活锁不会被阻塞,而是不停检测一个永远不可能为真的条件。除去进程本身持有的资源外,活锁状态的进程会持续耗费宝贵的CPU时间。

最后,进程会处于饥饿状态是因为持续地有其它优先级更高的进程请求相同的资源。不像死锁或者活锁,饥饿能够被解开。例如,当其它高优先级的进程都终止时并且没有更高优先级的进程到达。

㈦ 龙珠激斗里两把锁是什么资源

星龙之力,龙力之源,探索

㈧ 死锁的产生原因是什么

产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之
一不满足,就不会发生死锁。
死锁的解除与预防:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和
解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态
的情况下占用资源。因此,对资源的分配要给予合理的规划。