第一种:继承Thread类,重写该类的run()方法作为线程执行体。
第二种:实现runnable接口,创建实现类的对象作为Thread对象的target来创建线程。
第三种:实现Collable接口多了一个返回值,且线程执行体不是run方法了,而是call()方法。
此外,FutrueTask类来包装Callable对象,对于call()返回值使用Future接口的实现类FutureTask类来封装。
使用FutureTask 对象作为Thread对象的target创建并启动新线程。
调用FutureTask 对象的get()方法来获得子线程执行结束后的返回值。
比较:
第一种:
优点:编写简单,访问当前线程直接用this即可获得当前线程。
缺点:不能再继承其他类。
第二种和第三种差不多:
优点:可以继承、实现其他的类、接口。
当多个线程共享同一个target对象时,可同时处理同一资源。
缺点:只能通过Thread.currentThread()方法来访问当前线程。
线程的生命周期(5种状态)
新建(new) : 和其他java对象一样,由虚拟机为其分配内存,并初始化成员变量的值。
就绪(Runnable) : 当线程对象调用start()方法之后,线程处于就绪状态,java虚拟机会为其创建方法调用栈和程序计数器(pc)。此时,线程仍没有开始运行,只是等待执行。
可以通过Thread.sleep(1)让主线程睡眠1毫秒,让子线程立即执行。
运行(Running) : 如果就绪态的线程获得CPU,那么该线程就处于运行态
阻塞(Blocked) :
当发生以下几种情况,将发生阻塞
1.调用sleep()
2.调用一个阻塞式IO方法,该方法返回之前,该线程阻塞
3.试图获得一个同步监视器,但该同步被其他线程所持有。
4.线程等待通知(notity)
5.调用线程suspend()方法将线程挂起。
对应的解除阻塞:
1.调用sleep()方法经过指定时间
2.io方法已返回
3.线程成功获得同步监视器
4.其他线程发出通知
5.调用resume()方法解除挂起
死亡(Dead) 线程结束就是死亡
1.run()或call()方法执行完毕,正常结束
2.线程抛出一个未捕获的Exception或Error
3.直接调用stop()结束
注意:已经死亡的线程,不会在通过start()重新调用,就像一个已经真正死亡的生物不会再复活一样。
注意:只有就绪态的线程才能够到运行态,阻塞态是先到就绪态,才能够被运行。有一个yield()方法,可以将运行态线程-->就绪态。
并发和并行
并发:并发是指在同一时刻只有一条指令在被执行,只不过多个指令在快速的轮换执行,看上去就像是在同步执行一样。
并行:并行是指在同一时刻有多条指令在多个处理器上同时执行。