Java多线程的创建

概述

什么是线程

  • 线程(Thread)是一个程序内部的一条执行流程。

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

多线程是什么

  • 多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)。

如何在程序中创建出多线程

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

多线程的创建

多线程的创建方式一:继承Thread类

  1. 定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
  2. 创建MyThread类的对象
  3. 调用线程对象的start()方法启动线程(启动后还是执行run方法的)

方式一优缺点:

  • 优点:编码简单
  • 缺点:线程类以及继承Thread类,无法继承其他类,不利于功能的扩展。

ThreadTest1类

public class ThreadTest1 {
    // main方法是由一条默认的主线程负责执行
    public static void main(String[] args) {
        // 创建MyThread线程类的对象代表一个线程
        Thread t = new MyThread();
        // 启动线程(自动执行run方法的)
        t.start();

        for (int i = 1; i < 5; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

 MyThread类

public class MyThread extends Thread{
    // 必须重写Thread类的run方法
    @Override
    public void run() {
        for (int i = 1; i < 5; i++) {
            System.out.println("子线程MyThread输出:" + i);
        }
    }
}

多线程的注意事项

1、启动线程必须是调用start方法,不是调用run方法。

  • 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
  • 只有调用start方法才是启动一个新的线程执行。

2、不要把主线程任务放在启动线程之前。

  • 这样主线程一直是先跑完的,相当于是一个单线程的效果了。

 线程创建方式二:实现Runnable接口

  1.  定义一个线程任务类MyRunnable接口,重写run()方法
  2. 创建MyRunnable任务对象
  3. 把MyRunnable任务对象交给Thread处理
  4. 调用线程对象的start()方法启动线程
Thread类提供的构造器说明
publci Thread(Runnable target)封装Runnable对象成为线程对象

 方式二的优缺点

  • 优点:任务类知识实现接口,可以继承其他类、实现其他接口,扩展性强
  • 缺点:需要多一个Runnable对象

ThreadTest2类

public class ThreadTest2 {
    public static void main(String[] args) {
        // 创建任务对象
        Runnable target = new MyRunnable();
        // 把任务对象交给一个线程对象处理
        new Thread(target).start();

        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

MyRunnable类

public class MyRunnable implements Runnable{
    //重写runnable的run方法
    @Override
    public void run() {
        // 线程要执行的任务
        for (int i = 1; i <= 5; i++) {
            System.out.println("子线程输出:" + i);
        }
    }
}

  线程创建方式二的匿名内部类写法

  1. 可以创建Runnable的匿名内部类对象
  2. 再交给Thread线程对象
  3. 再调用线程对象的start()启动线程 
public class ThreadTest2_2 {
    public static void main(String[] args) {
        Runnable target = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("子线程1输出:" + i);
                }
            }
        };

        // 简化形式1:
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("子线程2输出:" + i);
                }
            }
        }).start();

        //简化形式2:
        new Thread(() -> {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("子线程3输出:" + i);
                }
        }).start();

        new Thread(target).start();

        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

线程创建方式三:实现Callable接口

 前两种线程创建方式搜存在的一个问题

  • 假如线程执行完毕后有以下数据需要返回,他们重写的run方法均不能直接返回结果。
怎么解决这个问题?
  • JDK5.0提供了Callable接口和FutureTask类来实现(多线程的第三种创建方式)。
  • 这种方式最大的优点:可以返回线程执行完毕后的结果。

多线程的第三种创建方式:利用Callable接口、FutureTask类来实现

  1. 创建任务对象
    1. 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
    2. 把Callable类型的对象封装成FutureTask(线程任务对象)
  2. 把线程任务对象交给Thread对象
  3. 调用Thread对象的start方法启动线程
  4. 线程执行完毕后、通过FutureTask对象的get方法去获取线程任务执行的结果

 FutureTask的API

FutureTask提供的构造器说明

public FutureTask<>(Callable call)

把Callable对象封装成FutureTask对象
FutureTask提供的方法说明
public V get()throw Exception获取线程执行call方法返回的结果

线程创建方式三的优缺点 

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

ThreadTest3类

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class ThreadTest3 {
    public static void main(String[] args) throws Exception {
        // 创建一个Callable的对象
        Callable<String> call = new MyCallable(100);
        // 把Callable的对象封装成一个FutureTask对象(任务对象)
        // 未来任务对象的作用?
        // 1.是一个任务对象,实现了Runnable对象
        // 2.可以再线程执行完毕后,用未来任务对象调用get方法获取线程执行完毕后的结果
        FutureTask<String> f1 = new FutureTask<>(call);
        // 把任务对象交给一个Thread对象
        new Thread(f1).start();

        // 获取线程执行完毕后返回的结果
        // 注意:如果代码执行到这,假如上面的线程还没有执行完毕,这里的代码会暂停,等上面线程执行完毕后才会获取结果
        String rs = f1.get();
        System.out.println(rs);
    }
}

MyCallable类

import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {
    private int n;

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

    // 重写call方法
    @Override
    public String call() throws Exception {
        // 描述线程的任务,返回线程执行返回后的结果
        // 需求:求1~n的和返回
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
        }
        return "线程求出了1~" + n + "的和为:" + sum;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值