线程结束源码
❶ android 为什么不建议使用Thread.stop
当调用Thread.stop()方法时,会发生以下两种事情:
1. 即可抛出ThreadDeath异常,在线程的run()方法里面,任何一刻都可能抛出ThreadDeath Error,包括在catch或者finally语句中。
2. 释放该线程的所有锁。
当线程抛出ThreadDeath异常时,会导致线程的run()方法突然返回来达到停止该线程的目的。这个异常可以在该线程run()任意一个执行点抛出。原则上只要一调用thread.stop()方法,线程会立即停止,并抛出ThreadDeath error,查看了Thread的源代码后才发现,原先Thread.stop0()方法是同步的,而我们工作线程的run()方法也是同步,那么这样会导致主线程和工作线程共同争用同一个锁(工作线程对象本身),由于工作线程在启动后就先获得了锁,所以无论如何,当主线程在调用thread.stop()时,它必须要等到工作线程的run()方法执行结束后才能进行。
因此,thread.stop()是不安全的,主要针对于于:释放改线程所持有的所有的锁,而锁的突然释放会导致被保护的数据的不一致性。
正确停止线程总结起来是以下三点:
1. 使用violate boolean 变量来表示线程是否停止;
2. 停止线程时,需要调用停止线程的interrupt()方法,因为线程有可能在wait()或者sleep(),提高停止线程的及时性;
3. 对于blocking IO的处理,尽量使用interruptibleChannel来代替 blocking IO。
❷ 如何优雅地结束一个线程
首先谢谢邀请
在本文中,我们将讨论结束java线程的简洁方法,这是必要的,因为Java已经弃用了Thread.stop()方法。
Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit由于一些潜在的线程安全问题, Oracle已弃用 。很少有公认的和广为接受的方法来实现这一点,在本文中,我们将讨论2 个用Java结束线程的方法。
使用标志
中断线程。
1.使用标志
一种简单的方法是使用线程来指示线程是否正在运行,并使用此标志根据您的要求采取纠正措施,下面是一个示例代码,概述了如何使用标志来杀死Java线程。
在上面的例子中。我们可以通过将运行变量设置为false来控制执行。在我们的示例中,我们使用AtomicBoolean了并发,如果您不想使用它(不推荐),您需要确保Boolean您在代码应该是易变的。可以使用 volatile代替他。
2.中断线程
以上代码看起来不错,但在采取上述方法之前需要考虑一些要点
如果我们有很多线程,它将变得更加复杂,我们需要确保使用join()方法完成这些线程。
我们真的需要定义一个布尔标志,因为Java已经使用中断标志提供了这个功能吗?
在这个代码块中有几件非常重要的事情
我们不会吞下异常,而是将其传递给系统,以确保系统根据此异常采取纠正措施
在上面的例子中,我们捕获InterruptedException并立即用于立即 Thread.currentThread().interrupt() 中断我们的线程。这是必需的,因为一旦抛出异常就中断了中断标志,并且如果我们的代码在嵌套循环中运行,它可能会导致一些问题。
总而言之,如果你仍然想要使用标志方法,那么Thread.interrupt()结束java线程的首选/推荐方法是你可能必须等待所有阻塞操作完成才能使用基于标志的逻辑。
文版权归是三僡然所有,转载请标明出处。欢迎转载,欢迎评论,欢迎分享。如果你有文章想分享可以联系我。
❸ 线程池中空闲的线程处于什么状态
一:阻塞状态,线程并没有销毁,也没有得到CPU时间片执行;
源码追踪:
for (;;) {
...
workQueue.take();
...
}
public E take()...{
...
while (count.get() == 0) { / /这里就是任务队列中的消息数量
notEmpty.await();
}
...
}
public final void await()...{
...
LockSupport.park(this);
...
}
继续往下:
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, 0L);
setBlocker(t, null);
}
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
//线程调用该方法,线程将一直阻塞直到超时,或者是中断条件出现。
public native void park(boolean isAbsolute, long time);
上面就是java11线程池中阻塞的源码追踪;
二.对比object的wait()方法:
@FastNative
public final native void wait(long timeout, int nanos) throws InterruptedException;
还有Thread的sleep() 方法:
@FastNative
private static native void sleep(Object lock, long millis, int nanos)throws...;
可见,线程池中使用的阻塞方式并不是Object中的wait(),也不是Thread.sleep() ;
这3个方法最终实现都是通过c&c++实现的native方法.
三.在<<Java虚拟机(第二版)>>中,对线程状态有以下介绍:
12.4.3状态转换
Java语言定义了5种线程状态,在任意一个时间点,一个线程只能有且只有其中的一种
状态,这5种状态分别如下。
1)新建(New):创建后尚未启动的线程处于这种状态。
2)运行(Runable):Runable包括了操作系统线程状态中的Running和Ready,也就是处于此
状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间。
3)无限期等待(Waiting):处于这种状态的线程不会被分配CPU执行时间,它们要等待被
其他线程显式地唤醒。以下方法会让线程陷入无限期的等待状态:
●没有设置Timeout参数的Object.wait()方法。
●没有设置Timeout参数的Thread.join()方法。
●LockSupport.park()方法。
4)限期等待(Timed Waiting):处于这种状态的线程也不会被分配CPU执行时间,不过无
须等待被其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程
进入限期等待状态:
●Thread.sleep()方法。
●设置了Timeout参数的Object.wait()方法。
●设置了Timeout参数的Thread.join()方法。
●LockSupport.parkNanos()方法。
●LockSupport.parkUntil()方法。
5)阻塞(Blocked):线程被阻塞了,“阻塞状态”与“等待状态”的区别是:“阻塞状态”在等
待着获取到一个排他锁,这个事件将在另外一个线程放弃这个锁的时候发生;而“等待状
态”则是在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将
进入这种状态。
结束(Terminated):已终止线程的线程状态,线程已经结束执行。