多线程的实现方式

155 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

大家好,我是尚影嫣🌷,一名Java后端程序媛。如果您喜欢我的文章,欢迎点赞➕关注❤️,让我们一起成为更好的我们~🥰

多线程的实现方式

使用实现多线程有四种方式:

  1. 继承Thread类;
  2. 实现Runnable接口;
  3. 使用Callable和FutureTask实现有返回值的多线程;
  4. 使用ExecutorService和Executors工具类实现线程池(如果需要线程的返回值,需要在线程中实现Callable和Future接口)

线程池ExecutorService和工具类Executors优点:可以根据实际情况创建线程数量,且只需要创建一个线程池即可,也能够通过Callable和Future接口得到线程的返回值,程序的执行时间与线程的数量紧密相关。缺点:需要手动销毁该线程池(调用shutdown方法)。

(一) 继承Thread类

继承Thread类的优点:简单,且只需要实现父类的run方法即可(start方法中含有run方法,会创建一个新的线程,而run是执行当前线程)。缺点是:Java的单继承,如果对象已经继承了其他的类则不能使用该方法。且不能获取线程的返回值

package yanf.thread;

public class MyThread extends Thread {

    /**
     * run方法里面是线程要执行的任务方法
     */
    @Override
    public void run() {
        // 这里的代码是一条新的执行路径
        // 这个执行路径的触发方法,不是调用run(),而是调用thread对象的start()来启动任务
        for (int i = 0; i < 10; i++) {
            System.out.println("锄禾日当午 " + i);
        }

    }
}

(二) 实现Runnable 接口

实现Runnable接口优点:简单,实现Runnable接口必须实现run方法。缺点:创建一个线程就必须创建一个Runnable的实现类,且不能获取线程的返CallabTask优点:可以获取多线程的返回值。缺点:每个多线程都需要创建一个Callable的实现类。

package yanf.thread;

/**
 * 用于给线程进行执行的任务
 */
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+",runnable---"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("发现了中断标记,我们这个线程自杀掉");
                return;
            }
        }

    }
}

(三) 通过Callable和FutureTask创建线程

package yanf.thread;

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

public class MyCallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. 创建callable对象
        Callable<Integer> call = new MyCallable();
        // 2. 创建任务
        FutureTask<Integer> task = new FutureTask<>(call);
        // 判断子线程是否执行完毕
//        task.isDone();
        // 断子线程没执行完毕也可以取消掉
//        task.cancel(true);
        // 3. 启动线程
        new Thread(task).start();
        // 调用了get()方法,主线程会等待子线程执行完成的结果
        Integer integer = task.get();
        System.out.println("返回值是:" + integer);
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }

    }

    static class MyCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
            return 100;
        }
    }
}