【JavaSE】多线程的实现继承Thread类,实现Runnable接口,实现Callable<V>接口

一、线程是什么

我们都知道进程是一个程序在系统中运行的一个周期。但是一个进程在运行的过程中,不一定只执行一项任务。所以就要引入线程。
线程就是进程进行分支任务的时候,每一个任务就称为一个线程。
main方法也是一个线程,他是所有分支线程的主线程

线程与进程的比较

  • 与进程相比,线程更加的"轻量级",创建、撤销一个线程比启动、撤销一个进程开销要小的多,并且一个进程中的所有线程共享此进程的所有资源。
  • 没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。
  • 进程是操作系统资源调度的基本单位,进程可以独享资源。线程需要依托于进程提供的资源,无法独立申请操作系统资源。线程是OS任务执行的基本单位。

二、多线程的实现

1.通过继承Thread类来实现多线程

  • 创建一个类继承Thread类覆写run()方法,然后在主线程main中调用此类对象的start()方法启动线程。
  • Tread类中的start()方法是启动线程的根本无论哪种方式实现多线程,线程启动一定调用Thread类提供的start()方法!
  • 每个对象线程的start()方法只能调用一次,多次调用会有异常。
  • start()方法主要就是让JVM给此线程分配它所需要空间和资源然后在JVM中回调此对象的run()方法。
  • 代码如下:
class MyThread extends Thread{
    public void run(){
        System.out.println("1");
        System.out.println("2");
        System.out.println("3");
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}

2.实现Runnable接口来实现多线程

  • 创建一个类继承Runnable接口,创建这个类的对象,将对象作为参数传入Thread的有参构造中
  • 用Thread的有参构造方法创建Thread的对象调用start启动。
  • 这个接口的子类对象要运行线程还是得调用,Thread的start方法。
  • 为什么要将Runnable接口的子类对象传递给Thread的构造函数。
    因为,自定义的run方法所属的对象是Runnable接口的子类对象。
    所以要让线程去找指定对象的run方法。就必须明确该run方法所属对象。
    其实Thread底层的run()方法也只是调用了一下传入的runnable的对象的run()方法
@Override
public void run() {
	if (target != null) {
		target.run();
	}
}
  • 代码如下:
class MyThread implements Runnable{
    private Integer s1 = 10;
    private String name;
    public MyThread(String name) {
        this.name = name;
    }
    public void run(){
        for(int i=0; i<10; i++){
            System.out.println(this.name+"、"+s1--);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread run = new MyThread("张三");
        Thread s1 = new Thread(run);
        Thread s2 = new Thread(run);
        Thread s3 = new Thread(run);
        s1.start();
        s2.start();
        s3.start();
    }
}
  • 使用Runnable接口实现的多线程程序类可以更好的描述共享的概念。
  • 并且实现Runnable接口的子类创建的对象,可以更好的分划任务,每个对象都可以分开传入Thread类从而启动线程。
  • 实现Runnable接口的类和Thread类是一个典型的代理模式,将Runnable接口的类对象传入Thread类,Thread类帮忙调用start()方法去底层分配空间和资源,然后回调run()方法进行真实业务如图:
    在这里插入图片描述
  • 需要注意的是,Thread类也实现了runnable接口,所以它自己的对象也可以作为参数传入Thread的构造方法中。

3.使用Callable接口 实现多线程

  • Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需 要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程
  • Thread类和Runnable接口都不允许声明检查型异常,也不能定义返回值。没有返回值这点稍微有点麻烦。不能声明抛出检查型异常则更麻烦一些。
  • 接口的定义如下:
public interface Callable<V> {
    V call() throws Exception;
}
  • Callable需要依赖FutureTask,用于接收运算结果。一个产生结果,一个拿到结果。FutureTask是Future接口的实现类,也可以用作闭锁。
  • Callable具体实现多线程的过程如图:
    在这里插入图片描述
    更加详细的过程可以查看Callable源码,多线程实现具体代码实现如下:
class MyThread implements Callable<String>{
    private int ticket = 10;
    public String call() throws Exception{
        while(this.ticket>0){
            System.out.println("还剩票数:"+this.ticket--);
        }
        return "票卖完了";
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException,ExecutionException {
        FutureTask<String> task = new FutureTask<>(new MyThread());
        Thread t = new Thread(task);
        t.start();
        Thread t1 = new Thread(task);
        t1.start();
        System.out.println(task.get());
    }
}
Callable 和 Runnable的区别

(1)Callable规定的方法是call(),而Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call()方法可抛出异常,而run()方法是不能抛出异常的。
(4)运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。
(5)它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
(6)通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
(7)Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值