`
jag522
  • 浏览: 33939 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

liveness hazard—死锁,活锁,饥饿

阅读更多

 在java多线程编程中,一不小心就会引起活性危险(liveness hazard),需要非常谨慎。
liveness可以翻译成活性,如果线程的活性好,说明运行状态不错,能得到CPU的有效处理;反之则线程可能处于死锁、饥饿、活锁等危险状态。
-----------------------------------------------------------------------------------------------------------------------------------------
什么是死锁,举个简单的例子:两只山羊过独木桥,它们同时走到桥中间,结果都堵在中间动弹不得。在这个例子中,可以把一只山羊在桥上走过的路比喻成资源,两只山羊同时在请求对方占有的资源。在java中,这种资源可以理解为对象的监视锁。

以下四个条件若同时满足,则可能会引起死锁:
相互排斥(Mutual exclusion):资源不能被共享,只能由一个线程使用。
请求与保持(Hold and wait):已经得到资源的线程可以再次申请新的资源。例如,线程A和B都需要访问一个文件,同时需要用到打印机,线程A得到了文件资源,线程B得到了打印机资源,但两个进程都不能获得全部的资源。
不可剥夺(No pre-emption):已经分配的资源不能从相应的线程中被强制地剥夺,即使该线程处于阻塞状态。
循环等待(Circular wait):系统中若干进程组成环路,该环路中每个线程都在等待相邻进程正占用的资源。例如,线程A在等待线程B,线程B在等待线程C,而线程C又在等待线程A。

死锁的解决办法有:加锁顺序、加锁时限、死锁检测,具体可参考:
http://ifeve.com/deadlock-prevention/
-----------------------------------------------------------------------------------------------------------------------------------------
什么是活锁,处于活锁状态中的线程对任务的处理丝毫取不到任何进展,其实活锁只是一种形象的比喻,和锁没有太大的关系。举个简单的例子:JMS中的死信问题,即消息监听器监听到消息后进行处理,但由于程序的bug,异常导致事务回滚,消息又回到了消息队列中,消息监听器再次监听到此消息后,又接着处理,又失败回滚,如此循环下去,此消息始终无法得到正确处理。
以下java代码也会引起活锁:
在a线程里:b.join(); 然后在b线程里:a.join()。两个线程都处于等待状态,如下图所示:



 

 
活锁的解决办法有:设置最大重试次数,超过该阈值后,监听自动停止;消息监听器监听到消息后,若不成功,则存表,不作回滚处理,事后再进行定时异步补偿处理;编程时避免两个线程互相join的情况,实际很少会出现这种情况。
-----------------------------------------------------------------------------------------------------------------------------------------

什么是饥饿,如果一个线程因为CPU时间全部被其他线程抢走而得不到CPU运行时间,这种状态被称之为“饥饿”。

 

例一:

先来了解读写锁的概念,假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。也就是说:读-读能共存,读-写(写-读)不能共存,写-写不能共存。这就需要一个读/写锁来解决这个问题。

 

再来看Java中的读写锁的实现类—ReentranctReadWriteLock默认使用非公平模式(不是先来先处理的模式)的情况下,如果某个线程想要读取资源,只要没有线程正在对该资源进行写操作且没有线程请求对该资源的写操作即可。如果读操作发生的比较频繁,我们又没有提升写操作的优先级,那么就会产生“饥饿”现象。请求写操作的线程会一直阻塞,直到所有的读线程都从ReentranctReadWriteLock上解锁了。如果一直保证新线程的读操作权限,那么等待写操作的线程就会一直阻塞下去,结果发生“饥饿”。

 

例二:

线程被永久堵塞在一个等待进入同步块的状态,因为其他线程总是能在它之前持续地对该同步块进行访问。

以下java代码会引起这种类型的饥饿:

synchronized(obj) {

while (true) {

  // .... infinite loop

}

}

 

例三:

高优先级线程吞噬所有的低优先级线程的CPU时间。例如在java中调用了Thread.setPriority方法设置了线程优先级,优先级低的线程始终得不到执行的机会,虽然线程优先级对于不同操作系统的实现方式不一样,即便设置了优先级也不一定会有效果,但还是有可能会出现这种情况。

 

饥饿的解决办法有:提升写请求的优先级或者采用公平策略;在synchronized方法或者块中避免无限循环;采用线程默认的优先级。
-----------------------------------------------------------------------------------------------------------------------------------------

总结:

死锁是两个线程同时在请求对方占有的资源

 

活锁是线程对任务的处理没有取得任何进展;

 

饥饿是一个线程在无限等待其他线程占有的但是不会往外释放的资源

 

参考资料:

Java Concurrency in PracticePartIII -> Chapter10 -> Avoiding Liveness Hazards

 

饥饿和公平

http://ifeve.com/starvation-and-fairness/

  • 大小: 24.2 KB
  • 大小: 1.3 KB
分享到:
评论
3 楼 jag522 2014-09-04  
yunchow 写道
以下java代码会引起活锁:
在a线程里:b.join(); 然后在b线程里:a.join()

这个会引起活锁,楼主测试过么


测试过,两个线程都会处于waiting状态。当然实际情况很少有人会写这样的代码:

package com.jag.util.concurrency;

public class LiveLockTest {

public static void main(String[] args) {
ThreadA a = new ThreadA();
ThreadB b = new ThreadB();
a.setB(b);
b.setA(a);
a.start();
b.start();
}

}

class ThreadA extends Thread {
private ThreadB b;
public void run() {
System.out.println("I'm in ThreadA");
try {
b.join();
System.out.println("Thread A finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void setB(ThreadB b) {
this.b = b;
}
}

class ThreadB extends Thread {
private ThreadA a;
public void run() {
System.out.println("I'm in ThreadB");
try {
a.join();
System.out.println("Thread B finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void setA(ThreadA a) {
this.a = a;
}
}
2 楼 yunchow 2014-09-04  
死锁是两个线程同时在请求对方占有的资源;
活锁是线程对任务的处理没有取得任何进展;
饥饿是一个线程在无限地等待其他线程占有的但是不会往外释放的资源。

总结的很到位啊
1 楼 yunchow 2014-09-04  
以下java代码会引起活锁:
在a线程里:b.join(); 然后在b线程里:a.join()

这个会引起活锁,楼主测试过么

相关推荐

    Liveness-Detection-(AndroidX).zip

    《AndroidX进阶活体检测技术详解》 在当今的移动应用开发中,安全与隐私保护日益重要,尤其是在金融、支付、社交等领域。活体检测技术作为一种强大的身份验证手段,可以有效防止欺诈行为,例如使用照片或视频冒充...

    活体检测方法调研,introduction_to_liveness_detection_liveness-detection-

    活体检测方法调研,introduction_to_liveness_detection_liveness-detection-introduction

    Void A fast and light voice liveness detection system.pdf

    标题中提到的“Void: A fast and light voice liveness detection system”指的是一个快速、轻量级的声音活体检测系统,它被命名为“Void”。在声音活体检测的领域,这是一个重要而具体的研究课题,尤其是考虑到随着...

    A New Multispectral Method for Face Liveness Detection.

    ### 新型多光谱人脸活性检测方法 #### 摘要与引言 本文提出了一种新型的基于梯度的多光谱人脸活性检测方法,旨在解决当前人脸识别系统容易被照片、模仿面具、人体模型等欺骗的问题。随着3D打印技术的进步,伪造...

    aws-liveness:AWS Liveness工具

    鲜活AWS Liveness工具。安装 npm i --save aws-liveness用法 const AWSLiveness = require ( 'aws-liveness' ) ;const { DynamoDB } = require ( 'aws-sdk' ) ;const awsLiveness = new AWSLiveness ( ) ;const ...

    Liveness-Detect:最简单的实时人脸识别API

    【Liveness-Detect: 实时人脸识别API详解】 在IT领域,人脸识别技术正逐渐渗透到我们的日常生活中,从安全监控到移动设备解锁,无处不在。"Liveness-Detect"项目提供了一个简单易用的实时人脸识别API,专为Django ...

    liveness and safetiy properties

    在计算机科学领域,特别是软件工程与系统验证方面,**活动性(Liveness)**和**安全性(Safety)属性**是两个核心概念,用于描述系统的行为特性。这两种属性对于确保系统的正确性和可靠性至关重要。本文将基于提供的...

    通信实验21

    在Liveness区域启用acceptance cycles,排除标记为end的无限循环,结果显示没有其他死循环,证明程序不会陷入无法前进的活锁状态。 总的来说,这个实验让学生深入理解了通信协议验证的过程,掌握了SPIN工具的使用,...

    Java线程总结.pdf

    线程的活跃性(liveness)问题是指线程在执行过程中可能遇到的某些问题,如死锁、饥饿、活锁等。死锁是指多个线程因争夺资源而永远地相互等待;饥饿是指线程由于其他线程总是优先执行而导致其无法获得足够的CPU时间...

    matlab的egde源代码-Face_Liveness_Detection:Face_Liveness_Detection

    matlab的egde源代码Face_Liveness_Detection Matlab的 NUAA数据库包含在Matlab文件夹中。 PRINT-ATTACK数据库可从下载。 CASIA数据库可从下载。 Matlab文件夹中包含LibSVM,LBP和HOOF工具箱。 所有* Train.m文件都...

    Face-Liveness-Detection:人脸活动检测-一种防止人脸识别系统中欺骗的工具

    脸部活跃度检测描述深度学习管道,能够发现人脸与合法人脸,并在人脸识别系统中执行反人脸欺骗。 它是在Keras,Tensorflow和OpenCV帮助下构建的。...该存储库的内容sample_liveness_data:包含样本数据集。

    k8s – livenessProbe – tcp存活性检测

    [root@k8s-master01 k8s-test]# cat livenessProbe-tcp.yaml apiVersion: v1 kind: Pod metadata: name: liveness-tcp namespace: default spec: containers: - name: liveness-tcp-container image: kone....

    《Java Concurrency in Practice》代码示例

    - **Liveness and Safety**:包含了死锁、活锁、饥饿等并发问题的实例,以及避免和解决这些问题的方法。 2. **jcip-annotations-src.jar**: 这个jar文件提供了书中的自定义注解,用于标记和验证并发代码的安全性...

    LCPD.zip_LCPD_descriptor_image processing_liveness detection_pha

    在计算机视觉领域,图像处理和生物识别技术是至关重要的部分,而“局部对比相位描述符”(Local Contrast Phase Descriptor,简称LCPD)正是其中的一种创新方法,尤其在活体检测(liveness detection)中表现出色。...

    liveness-android-sdk

    Android的Biblioteca Liveness。 安装说明 Gradle 没有arquivo build.gradle做项目,可用于: allprojects { repositories { maven { url " ...

    java oracle并发官方教程

    活跃度问题通常表现为死锁、饥饿和活锁。其中,死锁是指两个或多个线程因争夺资源而无限等待的情况;饥饿是指线程因无法获得所需资源而无法执行;活锁指的是线程不断重复执行某些操作,而无法向前推进。 ### ...

    liveness_src.zip

    内部排序:如果整个排序过程不需要借助外部存储器(如磁盘等),所有排序操作都是在内存中完成,这种排序就被称为内部排序。 就常用的内部排序算法来说,可以分为以下几类: * 选择排序(直接选择排序,堆排序) ...

    分布式系统中基于领导者选举的死锁检测算法

    8. 死锁检测算法的活性和安全性属性:活性(Liveness)是指算法能够保证在有限时间内对死锁做出反应;安全性(Safety)是指算法在检测过程中不会错误地标记一个未死锁的进程为死锁。 9. 分布式内存、多进程/多编程/...

    FaceLivenessDetection.zip_live detectness_liveness_moonml3_活体人脸_

    该资源名为“live detectness_liveness_moonml3_活体人脸”,从名字中我们可以看出,它基于moonml3模型,这是一种专为活体检测设计的深度学习模型。 活体检测的核心在于分析和理解人脸图像的细微特征,包括皮肤纹理...

    分布式系统中基于容错选举的死锁检测算法

    该算法的核心特性包括活性(liveness)和安全性(safety)。活性是指系统最终能够检测到死锁并解除它,而安全性是指系统在运行过程中不会错误地判断出现死锁。算法通过数学证明表明了其活性和安全性的属性。 实验...

Global site tag (gtag.js) - Google Analytics