2.创建线程的三种方式
导言
创建线程主要是有三种方式,第一种继承thread的类,第二种实现runnable接口。第三种实现callable接口
继承thread
定义 MyThread
首先我们来看第一种,继承thread,我们先自定义一个类,然后使他去继承thread类,继承完以后,我们需要去重写它里面的run方法,线程启动以后,它就会自动去调用这个 run方法。所以我们也要把自己的任务写在run方法里面,
package com.chenjie.executor.day02; public class MyThread extends Thread { @Override public void run() { System.out.println("将要执行的内容写在run方法里面"); } }
使用
下面我们来看看如何使用这个自定义线程。第一步,我们还要创建mythread的对象,第二步我们要调用它的start方法来启动这个线程,我们看一下执行结果是怎样的。
package com.chenjie.executor.day02; public class Main1 { public static void main(String[] args) { //创建线程 MyThread myThread=new MyThread(); //启动线程 myThread.start(); } }
结果
将要执行的内容写在run方法里面
Process finished with exit code 0
从执行结果来看,输出的内容和我们在run方法里面写的是一样的,第一种创业线程的方式呢我们就介绍完了。
实现runnable接口
我们再来看第二种创建线程的方式。第二种创建线程的方式呢是实现runnable接口
定义 task
我们还是先自定义一个类,然后呢让这个类去实现runnable不接口。它里面有个run方法,其实啊它也是实现了这个 runnable接口的。这里呢我们还需要注意一点,就是runnable它仅仅只是一个接口,它没有启动线程的能力搭配着thread的来使用。
package com.chenjie.executor.day02; /** * 自定义task */ public class Task implements Runnable{ @Override public void run() { System.out.println("将要执行的内容写在run方法中"); } }
使用
下面呢我们来看一下这个 runnable是如何搭配thread的来使用的。第一步,我们要创建task对象,第二步的我们要创建thread对象。我们在创建thread对象的时候,我们需要将task作为参数传递给他。第三步就是调用线程的start的方法来启动现场。
package com.chenjie.executor.day02; public class Main2 { public static void main(String[] args) { //创建自定义task Task task=new Task(); //创建线程,把task放进去 Thread thread = new Thread(task); //启动线程 thread.start(); } }
结果
我们来看一下执行结果是怎么样的。从运行结果来看,输出的内容和我们之前写的方案里面的内容是一样的,第二种创建线程的方式呢介绍完毕。
将要执行的内容写在run方法中
Process finished with exit code 0
实现callable
最后我们来看一下第三种创建线程的方式。第三种创业线程的方式呢是实现callable,我们还是先自定义一个类,然后呢去实现这个callable接口,和runnable还是有点不一样的。
自定义callable
runnable接口呢它只是仅仅只是执行任务,它里面没有说要返回任务的执行结果,但callable接口不同的是,他执行完任务以后,他需要返回一个执行结果,所以呢我们需要在callable接口后面指定一下这个返回结构的类型,也就是callable接口它是带泛型的,指定一个泛型,这里假设我们返回的结果是一个字符串,所以我们在后面写上一个string类型,指定完类型以后,我们就需要重写callable里面的一个call方法,那么这个 call方法和run方法的作用是一样的,只不过呢方法它里面多了一个范围值,因为他要返回任务执行的结果,那这个结果类型呢就是我们在上面刚刚指定的这个类型,这里需要说明一点,callable和runnable口他们都没用启动线程的能力,所以啊他们两人都要搭配线程来使用。
package com.chenjie.executor.day02; import java.util.concurrent.Callable; public class Result implements Callable<String> { @Override public String call() { String reslut="将要执行的内容写在run方法中"; return reslut; } }
使用
下面我们来看一下如何使用callable。第一步我们还要创建 result对象,第二步呢我们要借助 futuretask来获取这个结果的。
所以我们要创建一个futuretask对象,并且我们要将result这个对象传递给futuretask。第三步呢我们还是要创建一个线程,因为我们刚刚说了,无论是 callable还是runnable,他们都没有启动线程的能力,所以第三步还是要创建一个thread对象。同理,我们需要将futuretask的对象作为参数传递给 thread。thread现在启动以后呢去执行这个任务。再就是启动线程,到这里还没有完,这几步做完以后,我们仅仅只是将任务执行了,对吧?但是我们没有获取到任务返回的结果,那么获取任务返回的结果呢,就是通过futuretask的get方法,这里需要注意一点呢就是get方法它有一个异常要抛出来,这里我们就简单的给它捕获一下就可以了。
package com.chenjie.executor.day02; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Main3 { public static void main(String[] args) { //创建自定义task Result result = new Result(); //创建异步任务FutureTask FutureTask<String> futureTask=new FutureTask(result); //创建线程,把task放进去 Thread thread = new Thread(futureTask); //启动线程 thread.start(); try { String value = futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
结果
最后我们就输出我们拿到的结果,运行程序我们来看一下结果是怎样的。
将要执行的内容写在run方法中
Process finished with exit code 0
从运行结果来看,是吧?和我们在callable里面返回的结果是一致的。
至此呢我们创建线程的三种方式都介绍完毕了。
总结
那么再来总结一下今天的内容,今天我们主要讲了创建现成的三种方式
分别是继承thread的类,
实现runnable接口
实现callable接口
后面两者他们都没有启动线程的能力,所以他们都需要借助thread的来执行任务。这三种方式啊他们使用场景不相同的。
你比如说所谓的这种thread,它只是用单继承的情况,为什么?因为Java它只支持单继承,不支持多继承。所以你继承了所谓的类,就不能再继承其他类,这种方式的局限性太大了,所以不建议大家经常使用。至于后面两种方式是非常推荐大家在日常开发中使用的,runnable他就用到没有返回值的任务上面,而callable它就可以用在有返回值的任务上面。
可以发现第一个直接创建线程就可以使用了,第二个是实现runable,他是一个没有返回值的task,而第三个实现callable,我们可以发现在main3方法中创建了futureTask对象,其实这个对象就相当于我们第二步创建的那个task,只是我们在第三种方法中创建了更加细粒度的callable
本文来自博客园,作者:小陈子博客,转载请注明原文链接:https://www.cnblogs.com/cj8357475/p/16085943.html