从一个最基本的面试题开始,启动线程到底是start()还是run()?
Runnable runnable = () -> System.out.println(Thread.currentThread().getName()); Thread thread = new Thread(runnable); thread.run(); thread.start();
结果:
main
Thread-0
我们可以看到thread.run()是通过main线程执行的,而start()启动的才是一个新线程。run()只是在线程启动的时候进行回调而已,如果没有start(),run()也只是一个普通方法。
start()方法不一定直接启动新线程,而是请求jvm在空闲的时候去启动,由线程调度器决定。
Runnable runnable = () -> System.out.println(Thread.currentThread().getName()); Thread thread = new Thread(runnable); thread.start(); thread.start();
结果: Exception in thread "main" Thread-0 java.lang.IllegalThreadStateException at java.lang.Thread.start(Thread.java:705) at com.diamondshine.Thread.ThreadClass.main(ThreadClass.java:33)
原因我们可以从start()的源码得到,启动线程,会检测当前线程状态
public synchronized void start() { if (threadStatus != 0) //判断线程启动时的状态是否为new,如果不是,直接抛出异常 throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } }
PS:关于run()对应Thread和Runnable的区别,请参考上一篇博客并发和多线程(一)--创建线程的方式
相比线程启动,线程停止要复杂很多,有些方式虽然可以正常使用,但是可能存在某些风险,也是我们需要深入学习的地方。
这三种方式一般来说不会对我们有影响,因为是已废弃的方法,官方不推荐使用
关于stop()为什么废弃,可以查看:https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
有一个注意点,stop执行之后,会释放monitor的锁,而不是像某本并发书里面写的不释放锁,前面链接有说明。
suspend和resume是配套使用的,suspend本身不释放锁进行休眠,等待resume唤醒,这样很容易满足死锁的条件,所以官方不推荐使用。
我们中断一个线程通常使用Interrupt(),官方废弃stop(),推荐的也是通过Interrupt()实现中断。Interrupt()的特点是通知中断线程,而这个线程是否
中断选择权在于其本身,这是官方开发人员设计思想:需要被停止的线程可能不是你写的,对其了解可能不够,所以讲是否中断的选择权交于
其本身,Interrupt()只是给一个状态位而已。
终止线程的代码书写,取决于线程运行的方式,所以我们可以分类进行分析处理
2.1).一般情况
一般情况是指,没有调用sleep()、wait()等阻塞状态下的中断。
public static void main(String[] args){ Runnable runnable = () -> { int num = 0; while (num <= Integer.MAX_VALUE / 10) { if (num % 1000 == 0) { log.info("{}为1000的倍数", num); } num++; } }; Thread thread = new Thread(runnable); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); }
结果:最后一行
[Thread-0] INFO com.diamondshine.Thread.ThreadClass - 214748000为1000的倍数
从结果上看,interrupt()并没有 让线程停止,因为Integer的最大值2147483647
正确的代码应该是
public static void main(String[] args){ Runnable runnable = () -> { int num = 0; while (!Thread.currentThread().isInterrupted() && num <= Integer.MAX_VALUE / 10) { if (num % 1000 == 0) { log.info("{}为1000的倍数", num); } num++; } }; Thread thread = new Thread(runnable); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); }
结果:最后一行
[Thread-0] INFO com.diamondshine.Thread.ThreadClass - 96540000为1000的倍数
通过isInterrupted()的判断让线程提前中断了,而interrupt()的作用只是将Interrupted标志位置为true。
2.2).线程处于阻塞状态
public static void main(String[] args) throws InterruptedException{ Runnable runnable = () -> { int num = 0; try { while (!Thread.currentThread().isInterrupted() && num <= 100) { if (num % 100 == 0) { log.info("{}为100的倍数", num); } num++; } Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } }; Thread thread = new Thread(runnable); thread.start(); Thread.sleep(5000); thread.interrupt(); }
结果: 16:24:44.403 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 942000为1000的倍数 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.diamondshine.Thread.ThreadClass.lambda$main$0(ThreadClass.java:28) at java.lang.Thread.run(Thread.java:745)
主线程sleep休眠5000ms,然后执行interrupt(),而Thread-0只是执行代码时间很短,然后进入sleep,最后出现异常,程序停止运行。
线程在sleep或者其他阻塞的过程中,通过抛出异常来相应interrupt(),然后try catch进行捕获异常。
2.3).线程每次迭代都进行阻塞
原文:https://www.cnblogs.com/huigelaile/p/11715172.html