`
aa87963014
  • 浏览: 154359 次
  • 性别: Icon_minigender_1
  • 来自: 布尼塔尼亚
社区版块
存档分类
最新评论

构建更健壮的系统:如何干掉死循环的线程

阅读更多

 

为什么要干掉一个线程,这个和更健壮的系统有什么关系。

有时候我会想到一个问题,开发的系统基本上就是自己/测试团队测试了几遍然后上线。

上线后出现了不可预知的bug怎么办呢,例如出现了死循环或者部分逻辑有问题导致用户点击后会找出非常长的时间等待而且没办法进行其他操作。

 

java里面很多业务都用到了多线程,业务都放在线程池里面写

Thread.interrupt() 是无法终止一个非阻塞线程的,只能用Thread.stop()

stop()方法又不是推荐方法,不安全并@Deprecated了 但是又只有stop这个方法才能解决死循环

那么我们可以折中下,万不得已的情况才stop()

核心代码:先判断线程的状态,超时的线程又是RUNNABLE状态肯定是死循环了,其他情况使用中断方法。

 

			// 获取到了执行该任务的线程
			Thread execThread = (Thread) runner.get(obj);

			if (execThread == null) {
				return;
			}
			State state = execThread.getState();
			if (state == State.RUNNABLE) {
				execThread.stop();// 非阻塞线程才STOP,例如死循环
			} else {
				// 其他情况使用interrupt()方式,例如sleep、wait等等
			}
			future.cancel(true);

 

完整代码:中断线程池里面的一个FutureTask

 

public void killThread(FutureTask<?> future) {
		try {
			if (future.isDone()) {
				return;
			}
			// 处理长时间超时的线程

			// 利用反射,强行取出正在运行该任务的线程
			// Thread属性藏在FutureTask.Sync.runner属性,因为Sync是私有类需要多反射一次
			Field sync = FutureTask.class.getDeclaredField("sync");
			sync.setAccessible(true);
			Object obj = sync.get(future);

			Field runner = obj.getClass().getDeclaredField("runner");
			runner.setAccessible(true);

			// 获取到了执行该任务的线程
			Thread execThread = (Thread) runner.get(obj);

			if (execThread == null) {
				return;
			}
			State state = execThread.getState();
			if (state == State.RUNNABLE) {
				execThread.stop();// 非阻塞线程才STOP,例如死循环
			} else {
				// 其他情况使用interrupt()方式,例如sleep、wait等等
			}
			future.cancel(true);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

 

 

完整Class:

/**
 * 
 * 安全线程池,一个线程超时timeOut时间就杀掉这个线程。保证整个服务的稳定
 */
public class SafeExecutorService extends ScheduledThreadPoolExecutor {

	Logger logger = LoggerFactory.getLogger(SafeExecutorService.class);

	public SafeExecutorService(int corePoolSize) {
		super(corePoolSize);
	}

	long timeOut = 5;// 超时时间

	TimeUnit timeUnit = TimeUnit.MINUTES;

	ScheduledExecutorService timer = Executors
			.newSingleThreadScheduledExecutor();

	public SafeExecutorService(int corePoolSize, long timeOut, TimeUnit timeUnit) {
		super(corePoolSize);

		this.timeOut = timeOut;
		this.timeUnit = timeUnit;
	}

	@Override
	public Future<?> submit(Runnable task) {
		final FutureTask<?> future = (FutureTask<?>) super.submit(task);

		timer.schedule(new Runnable() {

			@Override
			public void run() {
				killThread(future);
			}
		}, timeOut, timeUnit);
		return future;
	}

	/**
	 * 
	 * 真正的终止任务
	 */
	public void killThread(FutureTask<?> future) {
		try {
			if (future.isDone()) {
				return;
			}
			// 处理长时间超时的线程

			// 利用反射,强行取出正在运行该任务的线程
			// Thread属性藏在FutureTask.Sync.runner属性,因为Sync是私有类需要多反射一次
			Field sync = FutureTask.class.getDeclaredField("sync");
			sync.setAccessible(true);
			Object obj = sync.get(future);

			Field runner = obj.getClass().getDeclaredField("runner");
			runner.setAccessible(true);

			// 获取到了执行该任务的线程
			Thread execThread = (Thread) runner.get(obj);

			if (execThread == null) {
				return;
			}
			State state = execThread.getState();
			if (state == State.RUNNABLE) {
				execThread.stop();// 非阻塞线程才STOP,例如死循环
			} else {
				// 其他情况使用interrupt()方式,例如sleep、wait等等
			}
			future.cancel(true);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		SafeExecutorService sss = new SafeExecutorService(2, 1,
				TimeUnit.SECONDS);
		sss.submit(new Runnable() {
			@Override
			public void run() {
				while (true) {
					System.out.println(1);
				}
			}
		});

		sss.submit(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000 * 500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});

	}
}

 

 

简单的介绍一下就是在执行一个任务的时候开计时器,时间到了就判断这个任务是否已经完成。

没完成的就肯定是有问题的,需要杀掉这个任务防止影响整个服务。

 

这种做法可以用在系统的构建上,来确保不会因为业务影响所有的服务。

 

1
0
分享到:
评论

相关推荐

    c# Task 多线程管理 v1

    在C#编程中,`Task`是用于异步编程的核心组件,它是在.NET Framework 4.0中引入的,作为对多线程处理的一种现代化、更高效的方式。`Task`类是`System.Threading.Tasks`命名空间的一部分,它提供了一种抽象的方式来...

    Java多线程编程实战指南 设计模式篇.rar

    设计模式则是解决常见编程问题的模板,通过应用这些模式,开发者可以构建更健壮、可维护的多线程系统。本实战指南将深入探讨如何在Java多线程环境中有效地运用设计模式。 一、Java多线程基础 1. 线程创建:Java提供...

    设计滚动字演示线程状态及改变方法

    在Java编程中,滚动字幕通常用于用户界面(UI)中的通知、提示或者展示动态信息。这个主题“设计滚动字演示线程状态及改变方法”主要涵盖了...理解并掌握这些知识点,能帮助我们构建出高效、稳定的滚动文字展示系统。

    多线程编程详解

    - **死锁定义**:两个或更多线程相互等待对方释放资源,导致无法继续执行。 - **避免死锁**:避免循环等待、合理设计资源获取顺序、超时和死锁检测机制等。 7. **Java并发工具** - **CountDownLatch**:用于同步...

    多线程解决mfc对话框未响应、卡死问题

    当不再需要工作线程时,不要直接杀死线程,而是应该让线程自行结束。可以设置一个标志,线程在检测到这个标志后主动退出。 通过以上策略,我们可以有效解决MFC对话框未响应或卡死的问题,提高应用程序的用户体验。...

    关于线程(java)两天的课件

    在Java中,有两种主要的方式来创建线程:继承Thread类并重写run()方法,或者实现Runnable接口并将其实例传递给Thread构造函数。继承Thread类的方法直接扩展Thread类,而实现Runnable接口则更适合多线程资源共享的...

    关于Java的基础线程部分

    以上是Java基础线程部分的一些核心概念和用法,理解和掌握这些知识将有助于初学者构建坚实的基础,以便进一步探索Java并发编程的高级主题。在实践中,不断练习和调试多线程代码,能更好地理解和应用这些概念。

    QT多线程

    QT框架中的多线程技术是实现并发执行任务的关键工具,特别是在开发复杂的桌面应用程序或系统级软件时,它能有效利用CPU资源...在实际开发中,结合QT的事件驱动模型和线程通信机制,可以构建出高效、健壮的多线程应用。

    Java多线程programmingShiZhanZhiNan(呵心篇).源码

    通过学习和实践这些知识点,开发者可以更好地利用Java的多线程特性,构建高效、稳定的应用。489.javamtia__Viscent这个文件很可能是该主题的一个具体示例或练习,包含了实际的多线程编程代码,值得深入研究。

    Delphi多线程详解

    在抢占式多任务环境中,如Win32,操作系统负责动态管理线程的执行顺序,即使某个线程陷入死循环,也不会阻塞其他线程的执行。而在协作式多任务环境中,如Windows 3.1,线程的执行依赖于应用程序主动让出控制权,一旦...

    用MFC编写VC多线程程序

    抢占式多任务环境下,操作系统负责调度线程的执行,即使某个线程陷入死循环,也不会影响其他线程的运行。而协作式多任务则需要应用程序配合,一旦某个程序耗尽了分配的时间,必须主动交出控制权,否则会导致系统挂起...

    Java+并发性和多线程

    理解并熟练掌握Java的并发性和多线程技术,能帮助开发者编写出高效、稳定、可扩展的并发程序,对于大型分布式系统的构建至关重要。通过阅读"Java+并发性和多线程.pdf"这份文档,你将能够深入理解这些概念,并能够在...

    MCA 多线程&高并发.zip

    - **活锁**:线程不断尝试获取资源但总是失败,导致无尽循环。 - **饥饿**:线程长时间无法获得所需资源。 - **Java并发工具类**:如Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(计数器)...

    基于Java多线程技术的聊天系统设计与开发.pdf

    《基于Java多线程技术的聊天系统设计与开发》这篇文档详细阐述了如何利用Java的多线程特性构建一个聊天系统。系统的核心在于处理并发的客户端连接和信息传输,主要涉及以下几个关键知识点: 1. **Java多线程**:...

    java 多线程编程指南

    在Java编程领域,多线程是一项至关重要的技术,它允许程序同时执行多个任务,从而提高系统效率和响应性。这份“Java多线程编程指南”深入探讨了这一主题,为中级到高级的Java开发者提供了宝贵的资源。 首先,多线程...

    java多线程和并发

    在现代计算机系统中,多核处理器的普及使得并发执行任务成为可能,而Java作为一门跨平台的编程语言,提供了丰富的工具和机制来支持多线程编程和并发控制。 1. **线程基础**: - **线程定义**:线程是程序执行的...

    Java 多线程 设计模式

    当将多线程与设计模式结合时,我们可以构建出更加高效、稳定且易于维护的并发系统。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程的方式,一是通过实现`Runnable`接口,二是继承`Thread`类。推荐...

    界面线程创建

    当界面线程运行时,它会接收到操作系统发送的消息,并通过消息循环处理这些消息。在MFC中,消息循环由`Run`成员函数控制,如: ```cpp int CMyUIThread::Run() { MSG msg; while (GetMessage(&msg, NULL, 0, 0)) ...

Global site tag (gtag.js) - Google Analytics