一 体系化深入学习并发编程由简入繁系统梳理并发知识点

多线程并发基础线程的正确启动如何停止线程正确地停止线程 判断线程中断的相关方法线程的生命周期 类和类中关于线程的方法 .sleep() .join() .yield() 线程的重要属性 线程的未捕获异常 多线程的利与弊 对象发布和初始化的安全问题 何时需要考虑并发安全问题 线程性能问题源码
实现线程的方式
Java实现多线程到底有几种方式呢?在看面试题的时候,多数都说是两种,但是在网上总会看到不同的声音,所以查阅了Java的官方文档,明确说明了只有两种实现线程的方式,而其他实现线程的方式无非是对这两种方式的再包装
There are two ways toa newof .
One is toa class to be aof .
The other way toais toa class thatthe.
**
继承类
public class ThreadStyle extends Thread{@Overridepublic void run() {System.out.println("使用Thread类实现线程");}public static void main(String[] args) {new ThreadStyle().start();}}
这种方式是通过继承类来实现多线程
它的本质是重写run()方法
实现接口
这种方式是通过实现接口,将实例传入类来实现多线程
public class RunnableStyle implements Runnable{@Overridepublic void run() {System.out.println("使用Runnable实现线程");}public static void main(String[] args) {new Thread(new RunnableStyle()).start();}}
而这种方式的本质是调用.run(),也就是调用传入的实例中重写的run()方法
/* What will be run. */private Runnable target;...@Overridepublic void run() {if (target != null) {target.run();}}
两种方式的比较
实现接口通常更实用
Java不允许多继承,继承了类,就不能继承其他类,而接口可以多实现实现接口可以使用线程池,减少线程创建和销毁的损耗利于代码的解耦 线程的正确启动
为什么启动线程要用start方法而不是run方法,它们有什么区别呢?
run方法和start方法的比较
public class StartAndRun {public static void main(String[] args) {Runnable r = () ->{System.out.println(Thread.currentThread().getName());};//直接调用run方法r.run();//调用start方法new Thread(r).start();}}
打印结果如下
mainThread-0
直接运行run方法,并没有真正的启动线程,而是像普通对象一样,调用了成员方法 。
而start方法才是真正地启动了线程
深入start方法 1.start方法的调用
start方法并不是一执行,就马上开始工作,它需要做好准备,获取了除了cpu资源的其他资源(栈、程序计数器等)后,进入就绪状态,等待JVM有空闲来执行它,如果JVM繁忙可能会继续等待 。
可见,start方法并不是按照启动顺序来作为执行顺序的
start方法的执行需要一个父线程,start方法的调度是作为父线程的指令来调度的(例如Main线程中执行这个命令)
2.start方法不可重复调用
public class CantReStart {public static void main(String[] args) {Thread thread = new Thread(()->{System.out.println(Thread.currentThread().getName());});thread.start();thread.start();}}
这里第二次调用start方法时会抛出一个异常
Exception in thread "main" java.lang.IllegalThreadStateException
这是因为线程执行完成后,转变为了终止状态,不能再回到之前的状态,所以抛出了非法线程状态异常,可以和后面的线程状态联系起来
状态不能再回到状态