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

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();
        }

    }


}

结果:
这里写图片描述

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值