【多线程】概述及三种创建方式

多线程的概述及创建方式

1.什么是线程?

线程是程序内部的一条执行流程,程序中如果只有一条执行流程,这个程序就是单线程的程序

2.多线程的概述

多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行),例如:消息通信、淘宝、京东系统都离不开多线程技术

3.创建多线程三种方式

Java是通过java.lang.Thread类的对象来代表线程的

  • 创建方式一:继承Thread类

    ①任务类继承Thread类,重写run方法

    ②测试类中,创建任务类对象

    ③调用继承来的start方法启动线程

    方式一优缺点:

    • 优点:编码简单,由于继承Thread类,可以直接调用Thread类的方法
    • 缺点:已经继承Thread类,不能再继承其他类,扩展性低

任务类:

//任务类继承Thread类,重写run方法
public class MyThread extends Thread{
    @Override
    public void run() {
        //子线程任务:打印整数1到10
        for (int i = 1; i <= 100 ; i++) {
            System.out.println("子线程" + i);
        }
    }
}

测试类:

public class Demo {
    public static void main(String[] args) {
        //测试类中,创建任务类对象
        MyThread t = new MyThread();
        //调用继承来的start方法启动线程
        t.start(); 
        //主线程任务:打印整数1到10
        for (int i = 1; i <= 100 ; i++) {
            System.out.println("主线程" + i);
        }
    }
}
  • 创建方式二:实现Runnable接口

    ①任务类实现Runnable接口,重写run方法

    ②测试类中,创建任务类对象,作为参数传递给Thread类的构造

    public Thread(Runnable target):封装Runnable对象成为线程对象

    ③Thread对象调用start方法启动线程

    方式二的优缺点

    • 优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强
    • 缺点:编码复杂,需要多一个Runnable对象,而没有直接继承Thread类,所以不能直接调用Thread类的方法

    任务类:

    //任务类类实现Runnable接口,重写run方法
    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            //子线程任务
            for (int i = 1; i <= 100; i++) {
                System.out.println("大炮:" + i);
            }
        }
    }
    

​ 测试类:

public class Demo {
    public static void main(String[] args) {
        //测试类中,创建任务类对象,作为参数传递给Thread类的构造
        MyRunnable target = new MyRunnable();
        //Thread对象调用start方法启动线程
        Thread t = new Thread(target);
        t.start();
        //主线程任务
        for (int i = 1; i <= 100; i++) {
            System.out.println("飞机:" + i);
        }
    }
}
  • 创建方式三:实现Callable接口

    线程执行完毕后有一些数据需要返回,前两种方式重写的run方法均不能直接返回结果
    解决问题:
    ① JDK5.0提供了Callable接口和FutureTask类来实现
    ②这种方式的最大优点:可以返回线程执行完毕后的结果

步骤:

  • 任务类实现Callable接口,重写call方法,和要返回的数据类型

    Callable为泛型接口,泛型为返回结果的数据类型

    任务类对象不能直接交给Thread类的构造,需要封装为FutureTask对象

  • 测试类中,创建任务对象,作为参数传递给FutureTask类的构造,得到FutureTask对象

  • 将FutureTask对象作为参数传递给Thread类的构造

  • Thread对象调用start方法启动线程

  • 线程执行完毕后,调用FutureTask对象的get方法,获取返回的数据

FutureTask类的方法:

public FutureTask(Callable call);:将Callable对象封装为FutureTask任务类对象

public V get() throws Exception:获取call方法的返回值,get方法是阻塞的

方式三的优缺点

  • 优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果
  • 缺点:编码复杂

任务类:

//任务类实现Callable接口,重写call方法,和要返回的数据
class MyCallable implements Callable<Integer> {
    //通过构造注入一个整数n
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
        }
        return sum;
    }
}

测试类:

public class Demo03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //测试类中,创建任务对象,作为参数传递给FutureTask类的构造,得到FutureTask对象
        FutureTask<Integer> ft = new FutureTask<>(new MyCallable(100)); //求1到100的整数和
        //将FutureTask对象,作为参数传递给Thread类的构造
        Thread t = new Thread(ft);
        //Thread对象调用start方法启动线程
        t.start();
        //线程执行完毕后,调用FutureTask对象的get方法,获取返回的数据
        System.out.println(ft.get()); //5050
    }
}
4.多线程的注意事项

(1)启动线程必须是调用start方法,不是调用run方法,直接调用run方法会当成普通方法执行,此时相当于还是单线程执行

(2)不能把主线程任务放在自动子线程之前,这样主线程一直是先跑完,相当于一个单线程的效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值