首页 / JAVA / Java线程核心基础(上)
Java线程核心基础(上)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java线程核心基础(上),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含2347字,纯文字阅读大概需要4分钟。
内容图文
![Java线程核心基础(上)](/upload/InfoBanner/zyjiaocheng/1327/56bf278ea9cf45eab658ee68339f067a.jpg)
Java线程核心基础(上)
一、实现多线程
根据Oracle官方文档,目前推荐的创建线程方法主要有两种,分别是继承Thread类和实现Runnable接口。通过阅读Thread类源码,可以发现继承Thread类需要重写run()方法,而实现Runnable接口会将自己实现的对象在new Thread()时,通过Thread构造函数传给Thread类中的target对象,并在调用run()方法时调用target.run(),下面让我们看源码。
/* What will be run. 这是Thread类中的target对象 */ private Runnable target; /* 当调用run()方法时会判断target是否为空, 如果是继承Thread类run()方法被重写,就不会执行以下代码了 */ @Override public void run() { if (target != null) { target.run(); } }
那么这两种方法哪一个更好呢? 实现Runnable接口更好,由于Java是单继承类但可以实现多个接口,如果继承了Thread类后续由于业务需要就不能继承新的类了,而实现Runable接口就没有这个问题。另外对于线程池,Callable,FutureTask,定时器,匿名内部类,lambda表达式等其他可以创建线程的方法,究其本质只是对以上两种方法进行了包装。
如果同时实现了两种方法会发生什么?即既传入Ruable对象,又重写run()方法。答案是会调用重写的run()方法,根据面向对象思想,子类重写父类方法,则父类原方法就无法调用了,target.run()也就无法执行了。
最后对这两种实现线程的方式一句话总结:一种创建线程的方式,两种实现执行单元的方式。
二、start() 和 run()方法的比较
start()方法可以启动新线程,并做准备工作,start()方法不能重复调用,会在第二次调用时抛出IIegalThreadStateException()。下面看一下源码
// 线程状态默认未启动 private volatile int threadStatus = 0; public synchronized void start() { // 判断线程是否已启动,已启动则抛出异常 if (threadStatus != 0) throw new IllegalThreadStateException(); // 加入线程组 group.add(this); boolean started = false; try { // 调用native方法创建线程 start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } }
run()方法直接调用就是普通方法,不会创建新线程执行,只用使用start()方法间接调用run()方法才能在新线程中执行。
三、如何正确停止线程
这个内容非常重要,停止线程应使用interrupt来通知,而不知强制停止。如何使用interrupt来请求停止线程呢? 有以下几种情况:
1. 普通情况run() 方法中没有sleep() 或wait()方法时,可以使用isInterrupted()方法进行判断。 ( 关于isInterrupted() 和 inInterrupted() 的区别后面会讲到)
2. 线程可能阻塞的情况, 当线程阻塞时收到interrupt中断会立即抛出异常响应中断,线程结束
3. 如果线程在每次工作迭代之后都阻塞,可以在迭代外层try/catch捕获异常并中断线程,如果在迭代内try/catch捕获异常,线程无法停止,因为sleep()或wait()方法会把interrupt标记位清除。
在实际生产开发过程中,对于停止线程的最佳的处理方式:
1. 优先选择: 传递中断
2. 不想或无法传递:恢复中断
3.不应屏蔽中断
错误的处理方式:在方法中吞掉中断。 可将异常抛到顶层在run()方法中处理。
另外,错误停止线程的方法
1. 被弃用的stop(), suspend()和resume() 方法, 使用stop()会使线程戛然而止,导致线程不能进行最后的收尾工作,可能对系统造成损害。 suspend()会挂起线程但是不会释放锁,可能会造成死锁。
2. 使用volatile设置Boolean标记位,这个方法相信很多人都会怀疑,啊?这个也是错误的?其实这个方法错就错在,虽然volatile能保证标记位对于线程随时可见,但是当线程阻塞时,是无法检查标记位的,如果没有其它线程唤醒,则阻塞线程会进入永久阻塞。 正确方法还是用interrupt()来通知要停止的线程。
四、线程的生命周期
线程总共有六个状态,New 已创建但还尚未启动的新线程,Runnable可运行,Blocked被阻塞,Waiting等待,Timed Waiting限期等待,Terminated终止。 一般而言会把 Blocked,Waiting,Timed Waiting都称为阻塞状态。
原文:https://www.cnblogs.com/vinsen/p/12328278.html
内容总结
以上是互联网集市为您收集整理的Java线程核心基础(上)全部内容,希望文章能够帮你解决Java线程核心基础(上)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。