并发编程系列(二)—常用多线程实现的方式

并发编程系列之基础篇(二)—常用多线程实现的方式

前言

大家好,牧码心今天给大家推荐一篇并发编程系列之基础篇(二)—常用多线程实现的方式的文章,希望对你有所帮助。具体内容如下

  • Thread,Runnable和Callable声明
  • 实例演示
  • 主要区别

概要

我们知道,创建线程通常的两种方式:一种是直接继承Thread,另外一种是实现Runnable接口。这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。
从Java 1.5开始,提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。Future接口是Java多线程Future模式的实现。Future模式是多线程设计常用的一种设计模式。
Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间后,我便可以从Future那儿取出结果。具体关于Future后续会详解。
本文将从这几种方式定义,具体实例和主要区别等方面介绍。

Thread,Runnable和Callable声明

  • Thread 是一个类,可以创建线程。Thread本身就实现了Runnable接口,具体定义如下:
 class Thread implements Runnable {...}
  • Runnable 是一个接口,该接口中只包含了一个run()方法,由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。如定义一个类A实现Runnable接口;然后通过new Thread(new A())的方式新建线程。具体定义如下:
public interface Runnable {
    public abstract void run();
}
  • Callable定义的是一个泛型接口,在它里面声明了一个call()函数,返回的类型就是传递进来的V类型,具体定义如下:
public interface Callable<V> {
    V call() throws Exception;
}

实例演示

  • 继承Thread类
/**
 * 继承Thead类
 * 目标:创建2个线程并发实现从1-100的累加
 */
public class CountThread01 extends Thread {
    private int start,end;

    private int num=0;

    public CountThread01(String name, int start, int end){
        super(name);
        this.start=start;
        this.end=end;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行");

        for (int i =start; i <=end; i++) {
            num+=i;
        }
        System.out.println(Thread.currentThread().getName()+"执行结束,num="+num);
    }

    public static void main(String[] args) throws InterruptedException {
        int start=0,mid=50,end=100;
        CountThread01 t1=new CountThread01("线程1",start,mid);
        CountThread01 t2=new CountThread01("线程2",mid+1,end);
        t1.start();
        t2.start();
        //合并2个线程
        t1.join();
        t2.join();
        System.out.println("结果:"+(int)(t1.num+t2.num));
    }
}

实现步骤如下:

  1. 继承 Thread 类
  2. 覆盖 run() 方法
  3. 直接调用 Thread#start() 执行
  • 实现Runnable接口方式
/**
 * 实现Runnable
 */
public class CountThread02 implements Runnable {

    private int start,end;

    private int num=0;

    public CountThread02(int start,int end){
        this.start=start;
        this.end=end;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行");
        for (int i =start; i <=end; i++) {
            num+=i;
        }
        System.out.println(Thread.currentThread().getName()+"执行结束,sum="+num);
    }

    public static void main(String[] args) throws InterruptedException {
        int start=0,mid=50,end=100;
        CountThread02 count1=new CountThread02(start,mid);
        CountThread02 count2=new CountThread02(mid+1,end);
        Thread t1=new Thread(count1,"线程1");
        Thread t2=new Thread(count2,"线程2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("结果:"+(int)(count1.num+count2.num));

    }
}

实现步骤如下:

  1. 实现Runnable接口;
  2. 执行Runnable实例,作为入参,创建Thread实例;
  3. 执行Thread#start方法
  • 实现Callable接口,结合FutureTask使用
/**
 * 实现Callable接口,结合FutureTask使用
 */
public class CountThread03 implements Callable<Integer> {

    private int start,end;

    private int num=0;

    public CountThread03(int start,int end){
        this.start=start;
        this.end=end;
    }

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"执行");

        for (int i =start; i <=end; i++) {
            num+=i;
        }
        System.out.println(Thread.currentThread().getName()+"执行结束,num="+num);
        return num;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int start=0,mid=50,end=100;
        int sum1=0,sum2=0;
        FutureTask<Integer> task1=new FutureTask<Integer>(new CountThread03(start,mid));
        FutureTask<Integer> task2=new FutureTask<Integer>(new CountThread03(mid+1,end));
        Thread t1=new Thread(task1,"线程1");
        Thread t2=new Thread(task2,"线程2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        if(task1.isDone()){
            sum1=task1.get();
        }
        if(task1.isDone()){
            sum2=task2.get();
        }
        System.out.println("结果:"+(int)(sum1+sum2));
    }
}

实现步骤如下:

  1. 实现Callable接口;
  2. 以Callable的实现类为参数,创建FutureTask实例;
  3. 将FutureTask作为Thread的参数,创建Thread实例;
  4. 通过 Thread#start 启动线程;
  5. 通过 FutreTask#get() 阻塞获取线程的返回值

主要区别

这几种方式都能创建线程,其不同点如下:

  • Thread 是一个类,而Runnable,Callable是一个接口;
  • 继承是单继承,接口能多实现,也能继承;
  • Callable可以直接获取返回结果,Thread和Runnable需要通过共享变量或者使用线程通信的方式获得返回结果;
  • Runnable可以用于“资源的共享”,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值