【JavaP6大纲】多线程篇:线程的生命周期,什么时候会出现孤儿进程,僵尸进程?它们之间的危害是什么?如何处理僵尸进程?

本文详细解读线程的生命周期阶段,探讨孤儿进程和僵尸进程的形成时机,分析它们可能带来的危害,并提供僵尸进程的三种处理方法:信号机制、杀死父进程和重启系统。

线程的生命周期,什么时候会出现孤儿进程,僵尸进程?它们之间的危害是什么?如何处理僵尸进程?

线程的生命周期

新建(new Thread):当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。例如:Thread t1=new Thread();
就绪(runnable):调用Thread类的start方法,线程已经被启动,进入就绪状态,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。
运行(running):线程获得CPU资源正在执行任务(执行run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束或者时间片结束。
堵塞(blocked:由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。阻塞结束后线程进入就绪状态。
堵塞的情况分三种:
(一)等待堵塞:执行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)同步堵塞:执行的线程在获取对象的同步锁时,若该同步锁被别的线程占用。则JVM会把该线程放入锁池中。
(三)其它堵塞:执行的线程执行sleep()或join()方法,或者发出了I/O请求时。JVM会把该线程置为堵塞状态。
说明:当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完成时。线程又一次转入就绪状态。
死亡(dead):当线程执行完毕(run方法运行结束)或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

什么时候会出现孤儿进程,僵尸进程?

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

危害

孤儿进程:孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。
僵尸进程:父进程还在运行但是子进程挂了,但是父进程却没有使用wait来清理子进程的进程信息,导致子进程虽然运行实体已经消失,但是仍然在内核的进程表中占据一条记录,这样长期下去对于系统资源是一个浪费。

僵尸进程处理

1、通过信号机制:子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。调用wait()或者waitpid(),让父进程阻塞等待僵尸进程的出现,处理完在继续运行父进程。
2、杀死父进程:当父进程陷入死循环等无法处理僵尸进程时,强制杀死父进程,那么它的子进程,即僵尸进程会变成孤儿进程,由系统来回收。
3、重启系统:当系统重启时,所有进程在系统关闭时被停止,包括僵尸进程,开启时init进程会重新加载其他进程。

在JNI编程中,获取Java对象实例时可能遇到的问题通常与JNI环境的正确使用、类方法的查找、以及对象生命周期的管理有关。以下是几个常见的问题及其修复方式: ### 获取Java对象实例时的常见问题及修复方式 1. **未正确获取JNIEnv指针** JNI函数的调用必须依赖于JNIEnv指针,它是线程相关的。如果在本地代码中未能正确获取或传递JNIEnv,可能导致调用失败或程序崩溃。 **修复方式**:确保在Java调用本地方法时,由Java虚拟机自动提供JNIEnv参数。在回调或异步调用中,应使用`JavaVM`接口获取当前线程的JNIEnv[^1]。 2. **类查找失败(FindClass返回NULL)** 在本地代码中通过`FindClass`获取Java类时,若类路径错误或类尚未加载,可能导致返回NULL,进而引发后续调用失败。 **修复方式**:确保传入`FindClass`的类名格式正确(如`"com/example/MyClass"`),并检查Java类是否存在于类路径中。可以使用`ExceptionCheck`或`ExceptionOccurred`来检测是否发生异常[^2]。 3. **方法ID获取失败(GetMethodID返回NULL)** 如果方法名或签名错误,`GetMethodID`会返回NULL,导致后续调用对象方法时失败。 **修复方式**:确保方法签名与Java方法的参数返回类型完全匹配。例如,`"()Ljava/lang/String;"`表示无参数并返回String的方法。可以使用`javap`工具生成正确的签名[^3]。 4. **对象生命周期管理不当** JNI中Java对象的引用分为局部引用全局引用。若在本地代码中长期持有Java对象而未创建全局引用,可能导致对象被提前回收。 **修复方式**:使用`NewGlobalRef`创建全局引用以长期持有对象,并在不再需要时调用`DeleteGlobalRef`释放引用。 5. **未处理异常(ExceptionPending)** JNI调用过程中若发生异常,后续的JNI函数调用可能无效,必须先清除异常或进行处理。 **修复方式**:在关键调用后使用`ExceptionCheck`或`ExceptionOccurred`检测异常,并根据情况处理异常或返回错误码。 ### 示例代码:正确获取Java对象并调用方法 ```cpp extern "C" JNIEXPORT void JNICALL Java_com_example_MyClass_callJavaMethod(JNIEnv *env, jobject /* this */) { jclass clazz = env->FindClass("com/example/JavaClass"); if (clazz == nullptr) { // 类未找到,处理错误 return; } jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); if (constructor == nullptr) { // 构造方法未找到,处理错误 return; } jobject javaObject = env->NewObject(clazz, constructor); if (javaObject == nullptr) { // 对象创建失败 return; } jmethodID methodId = env->GetMethodID(clazz, "sampleMethod", "()V"); if (methodId == nullptr) { // 方法未找到 return; } env->CallVoidMethod(javaObject, methodId); // 释放局部引用 env->DeleteLocalRef(javaObject); env->DeleteLocalRef(clazz); } ``` ###
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java程序员廖志伟

赏我包辣条呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值