重新认识Java线程创建的三种方式:
继承Thread类
1.通过继承Thread类创建Thread子类,并重写run方法。run方法的方法体表示线程类要完成的任务,因此也把run方法称为执行体。
2.创建Thread子类的实例对象,就是创建了线程对象。
3.调用start方法启动线程。
//线程类
public class xiancheng extends Thread{
@Override
public void run() {
//执行体
}
}
//启动方法
Thread th = new Thread();
th.start();
实现Runnable接口
1.定义Runnable接口的实现类,并重写接口的run方法。这个run方法同样是执行体。
2.创建Runnable实现类的实例对象,并依此实例作为Thread的target来创建Thread对象。Thread对象才是真正的线程对象。
3.调用线程对象的start方法启动线程。
//线程类
public class xiancheng implements Runnable{
@Override
public void run() {
//执行体
}
}
//启动方法
xiancheng xc = new xiancheng();
Thread th = new Thread(xc);
th.start();
通过Callable和Future创建线程
1.定义Callable接口的实现类,并重写call方法,此时call方法作为线程执行体,并且有返回值。
2.创建Callable实现类的实例对象,使用FutureTask类来包装该实例对象。此时FutureTask的对象封装了call方法得到返回值。 FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了 Future和Runnable接口
3.使用FutureTask对象作为Thread的target对象创建线程对象,start方法启动线程。
4.调用FutureTask对象的get方法可以获得线程结束的返回值。
//线程类
public class xiancheng implements Callable<Integer>{
@Override
public Integer call() throws Exception {
//执行体
return null;
}
}
//启动方法
xiancheng ab = new xiancheng();
FutureTask<Integer> ft = new FutureTask<>(ab);
Thread th = new Thread(ft);
th.start();
线程的运行状态(也叫生命周期,这里只分了5个,好像大家各有各的说法)
Java线程的5种状态分别是:
- 新建(new):新建了一个线程对象,此时并没有调用start方法
- 就绪(ready):线程创建以后被调用了start方法,该状态下线程位于可运行线程池中,等待被线程调度选中获得CPU的使用权(一个CPU同一时间只能运行一个线程),此时处于就绪(ready)状态。
- 运行(runnable):就绪状态的线程获得CPU的时间片之后开始运行,执行run方法中的代码,变为运行中(runnable)状态。
- 阻塞(blocked):表示线程阻塞于锁。阻塞是因为线程由于某种原因放弃CPU的使用权,暂时停止运行。直到线程回到就绪状态,才有机会重新获得CPU时间片再次进入运行状态。阻塞大致可分为三种:
- 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池。(wait释放持有的锁)
- 同步阻塞:运行的线程获取对象的同步锁时,若该同步锁被其他线程占用,JVM会把该线程放入锁池中。
- 其他阻塞:运行中的线程执行sleep()方法或者join()方法,或者发出I/O请求(如read是阻塞的),JVM会把线程设置为欸阻塞状态。当sleep超时,join()等待线程终止或者超时,或I/O处理结束,线程阻塞取消重新进入就绪状态。(注意,sleep状态是不会释放持有的锁的)
- 死亡(dead):线程执行完毕或者因为异常退出了run()方法,该线程结束生命周期。
参考:https://blog.csdn.net/evankaka/article/details/44153709#t3