线程的停止与回收

A01-04  线程的停止和回收

线程停止:当return语句被执行时,表示线程正常退出。

int Routine()
{
    printf("do something\n");
    return 0;                            //线程的主函数退出
}


return语句被执行,Routune()返回,线程退出

异常退出:

①当主线程退出的时候,所以的子线程都会退出

②这种异常退出会造成数据的不完整,破坏数据。应尽量避免这种情况

③如果需要异常终止,应该先保存数据

如何让线程正常终止

①设置标识量(在类中添加bool m_quitflag变量,用来标识线程的状态)
②等待线程的退出:
	MyTask task;
	task.m_quitflag = false;     //将状态设置为false
	task.Run();                         
	getchar();                   //按下“回车”,退出
	task.m_quitflag = true;      //将状态设置为true
	OS_thread::Join(&task);      //等待目标线程退出
Join()函数作用:
①等待目标线程退出
②回收这个线程的相关资源(因为线程的个数是有限的)
③注意:线程是不能自己回收自己的,(在类中调用OS_Thread::Join(this)是不可行的)如下:
#include 
   
    
#include 
    
     
#include "osapi/Thread.h"

class MyTask1 :public OS_Thread
{
private:
	virtual int Routine()
	{
		for (int i = 0; !m_quitflag && i < 10; i++)
		{
			printf("AAAAAA\n");
			OS_Thread::Sleep(1);		//使线程暂停1秒
		}
		printf("Task Exit...\n");
		/*此处可以添加数据的处理*/
		//OS_Thread::Join(this);		//此处线程调用了自己(回收自己),这个显然是不可行的
		return 0;
	}
public:
	bool m_quitflag;					//标识量,控制线程的状态
};

int main()
{
	MyTask1 a;
	a.m_quitflag = false;
	a.Run();				//a线程开始工作

	getchar();
	a.m_quitflag = true;
	OS_Thread::Join(&a);				//此处回收是可行的

	system("pause");
	return 0;
}
    
   
将m_quitflag封装进类中(防止破坏了封装性)如下:
#include 
     
      
#include 
      
       
#include "osapi/Thread.h"

class MyTask1 :public OS_Thread
{
private:
	bool m_quitflag;					//标识量,控制线程的状态

public:
	int Start()
	{
		m_quitflag = false;
		Run();
		return 0;
	}
	int Stop()
	{
		m_quitflag = true;
		Join(this);			//为何此处可以使用呢?是否与前面的说法冲突?
		/*
		这只是一个c++的对象,而不是线程实体。要区分
		*/
		return 0;
	}
private:
	virtual int Routine()
	{
		for (int i = 0; !m_quitflag && i < 10; i++)
		{
			printf("AAAAAA\n");
			OS_Thread::Sleep(1);		//使线程暂停1秒
		}
		printf("Task Exit...\n");
		/*此处可以添加数据的处理*/
		return 0;
	}

};

int main()
{
	MyTask1 a;
	a.Start();

	getchar();
	a.Stop();

	system("pause");
	return 0;
}
      
     
Join的调用位置:不能只看字面上的位置,而要从运行时的角度来看待问题

注:关于博客中的第三方库"osapi",可以通过访问http://www.afanihao.cn的共享代码模块中获

详情请参见http://www.afanihao.cn/的应用篇




### Java线程安全终止资源回收的最佳实践 在Java中,正确终止线程并确保资源被有效回收是一个重要的主题。以下是关于如何实现这一目标的关键点: #### 1. 使用标志位控制线程生命周期 为了安全地停止线程而不引发不可预测的行为,推荐使用一个布尔型的标志位来控制线程的运行状态。这种方式可以避免直接调用`stop()`方法带来的风险[^3]。 ```java public class SafeThread extends Thread { private volatile boolean running = true; @Override public void run() { while (running) { try { // 执行任务逻辑 doWork(); } catch (Exception e) { handleException(e); } } cleanupResources(); // 清理资源 } public void shutdown() { this.running = false; } private void doWork() throws Exception { // 模拟工作负载 } private void handleException(Exception e) { System.err.println("Error occurred: " + e.getMessage()); } private void cleanupResources() { System.out.println("Cleaning up resources..."); } } ``` 上述代码展示了如何通过设置`volatile`修饰符的布尔变量`running`来控制线程的退出,并在线程结束前清理必要的资源。 --- #### 2. 避免直接调用`stop()`方法 `stop()`方法已被标记为过时(deprecated),因为它可能导致死锁或其他不确定行为。取而代之的是采用协作式的线程终止机制,例如上文中提到的标志位控制法[^5]。 --- #### 3. 正确处理异常以防止意外终止 线程中的`run()`方法无法向外抛出受检异常(checked exceptions)。因此,在编写多线程应用时,应始终捕获可能发生的异常并妥善处理它们,以免因未被捕获的异常而导致整个程序崩溃。 --- #### 4. 利用`try-finally`块释放资源 无论线程是因为正常完成还是因为异常中断,都应当确保所有分配的资源能够得到及时释放。这可以通过`try-finally`结构来实现。 ```java @Override public void run() { Resource resource = null; try { resource = acquireResource(); process(resource); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // 恢复中断状态 System.err.println("Thread was interrupted."); } finally { releaseResource(resource); // 确保资源总是会被释放 } } private Resource acquireResource() { return new Resource(); } private void process(Resource resource) throws InterruptedException { // 模拟耗时操作 Thread.sleep(1000); } private void releaseResource(Resource resource) { if (resource != null) { resource.close(); } } ``` 此示例说明了即使发生异常,也会进入`finally`块执行资源释放的操作。 --- #### 5. 借助高级并发工具简化管理 对于复杂的多线程场景,建议使用`ExecutorService`框架代替手动创建和管理线程。它提供了更灵活的任务提交接口以及内置的支持用于优雅地关闭线程池[^4]。 ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); Runnable task = () -> { try { performTask(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("Task was interrupted."); } }; executor.submit(task); // 平滑关闭线程池 executor.shutdown(); } private static void performTask() throws InterruptedException { Thread.sleep(2000); System.out.println("Task completed."); } } ``` 利用`shutdown()`方法可以让线程池有机会完成已提交的任务后再完全停机,从而减少强制终止的风险。 --- #### 总结 以上介绍了几种常见的策略来保障Java线程的安全终止及其伴随的资源回收过程。合理设计应用程序架构、遵循良好的编码习惯是达成高效稳定系统的基石。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值