- Java并发编程之美
- 翟陆续 薛宾田
- 923字
- 2020-08-27 23:32:55
1.2 线程创建与运行
Java中有三种线程创建方式,分别为实现Runnable接口的run方法,继承Thread类并重写run的方法,使用FutureTask方式。
首先看继承Thread类方式的实现。
public class ThreadTest { //继承Thread类并重写run方法 public static class MyThread extends Thread { @Override public void run() { System.out.println("I am a child thread"); }
} public static void main(String[] args) { // 创建线程 MyThread thread = new MyThread(); // 启动线程 thread.start(); } }
如上代码中的MyThread类继承了Thread类,并重写了run()方法。在main函数里面创建了一个MyThread的实例,然后调用该实例的start方法启动了线程。需要注意的是,当创建完thread对象后该线程并没有被启动执行,直到调用了start方法后才真正启动了线程。
其实调用start方法后线程并没有马上执行而是处于就绪状态,这个就绪状态是指该线程已经获取了除CPU资源外的其他资源,等待获取CPU资源后才会真正处于运行状态。一旦run方法执行完毕,该线程就处于终止状态。
使用继承方式的好处是,在run()方法内获取当前线程直接使用this就可以了,无须使用Thread.currentThread()方法;不好的地方是Java不支持多继承,如果继承了Thread类,那么就不能再继承其他类。另外任务与代码没有分离,当多个线程执行一样的任务时需要多份任务代码,而Runable则没有这个限制。下面看实现Runnable接口的run方法方式。
public static class RunableTask implements Runnable{ @Override public void run() { System.out.println("I am a child thread"); } } public static void main(String[] args) throws InterruptedException{ RunableTask task = new RunableTask(); new Thread(task).start(); new Thread(task).start(); }
如上面代码所示,两个线程共用一个task代码逻辑,如果需要,可以给RunableTask添加参数进行任务区分。另外,RunableTask可以继承其他类。但是上面介绍的两种方式都有一个缺点,就是任务没有返回值。下面看最后一种,即使用FutureTask的方式。
//创建任务类,类似Runable public static class CallerTask implements Callable<String>{ @Override public String call() throws Exception { return "hello"; } } public static void main(String[] args) throws InterruptedException { // 创建异步任务 FutureTask<String> futureTask = new FutureTask<>(new CallerTask()); //启动线程 new Thread(futureTask).start(); try { //等待任务执行完毕,并返回结果 String result = futureTask.get(); System.out.println(result); } catch (ExecutionException e) { e.printStackTrace(); } }
如上代码中的CallerTask类实现了Callable接口的call()方法。在main函数内首先创建了一个FutrueTask对象(构造函数为CallerTask的实例),然后使用创建的FutrueTask对象作为任务创建了一个线程并且启动它,最后通过futureTask.get()等待任务执行完毕并返回结果。
小结:使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过set方法设置参数或者通过构造函数进行传递,而如果使用Runnable方式,则只能使用主线程里面被声明为final的变量。不好的地方是Java不支持多继承,如果继承了Thread类,那么子类不能再继承其他类,而Runable则没有这个限制。前两种方式都没办法拿到任务的返回结果,但是Futuretask方式可以。