首页 > 编程 > Java > 正文

java 多线程(一)---创建线程的三种方式Thread,Runnable,Callable与Future

2019-11-09 17:21:30
字体:
来源:转载
供稿:网友

1 前言

java中我们经常会遇到多线程问题,包括线程的互斥,同步,线程通信,线程池等一些问题,也是面试中经常问道的。这里做一个笔记。

本篇主要介绍创建线程的三种方式,后续会陆续介绍同步,线程通信等问题

2 继承Thread类

继承Thread类并复写run()方法,是一种很简单的方式,代码如下:

package thread;/** * Created by qiyei2015 on 2017/2/6. */public class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { String name = Thread.currentThread().getName(); System.out.PRintln(name + "已经运行"); }}

run()方法内就是线程体,可以做我们自己的工作。另外线程的启动是调用start()方法。

import thread.MyThread;public class Main { public static void main(String[] args) { new MyThread("线程一").start(); }}

结果: 这里写图片描述 可以看到线程已经运行起来了。

3 实现Runnable接口

这个是我们经常使用的方式之一,代码如下:

package thread;/** * Created by qiyei2015 on 2017/2/6. */public class MyTask implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + "已经运行"); }}

测试代码如下:

import thread.MyTask;public class Main { public static void main(String[] args) { //new MyThread("线程一").start(); new Thread(new MyTask(),"线程二").start(); }}

结果: 这里写图片描述 一般我们推荐的就是实现Runable接口这种方式来创建线程,这是因为由于java的单继承限制,我们继承了Thread类就不能再继承其他的类了。

4 Callable与Future创建线程

我们看到不管是Thread还是Runable接口,其run()都是无返回值的,并且无法抛出异常的,如果我们有需要返回值或者抛出异常怎么办?这个时候就需要用到Callable与Feature了。

先来看类的继承关系 这里写图片描述

可以看到Callable是一个接口,里面有个V call()方法,这个V就是我们返回值类型,同时还有Future相关的类,注意观察FutureTask类的构造函数,我们发现其中一个构造函数的参数是Callable类型,这里就把两个内联系起来了。Callable与Future的用法如下:

用法一:使用FutureTask来启动Callable线程 实现Callable接口的V call()方法,并构造FutureTask 对象,调用该对象的run()方法

import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class Main { public static void main(String[] args) { //new MyThread("线程一").start(); //new Thread(new MyTask(),"线程二").start(); callableTest1(); }private static void callableTest1(){ //这里指定返回String类型 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { System.out.println("Callable 已经运行啦"); return "this is Callable is running"; } }; FutureTask<String> futureTask = new FutureTask<String>(callable); futureTask.run(); try { if (futureTask.isDone()){ //任务完成 System.out.println(futureTask.get()); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }}

结果如下: 这里写图片描述

可以看到线程已经运行了,并且我们也收到返回值了。其中call()就是我们的线程体。

用法二:使用 ExecutorService线程池来提交Callable任务

这里我们主要用到线程池,有关线程池的问题后面再细讲。这里只需要知道怎么用就行。我们还是使用Future来获取返回的结果,代码如下:

import java.util.concurrent.*;public class Main { public static void main(String[] args) { //new MyThread("线程一").start(); //new Thread(new MyTask(),"线程二").start(); //callableTest1(); callableTest2(); } private static void callableTest2(){ ExecutorService executorService = Executors.newSingleThreadExecutor(); //这里指定返回Integer类型 Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("Callable 已经运行啦"); return 1024; } }; Future<Integer> futureTask = executorService.submit(callable); try { Thread.sleep(100); if (futureTask.isDone()){ System.out.println(futureTask.get()); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }}

结果: 这里写图片描述

好,本文到这里就结束了。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表