多线程的三种创建方式及各自的优缺点分析

50 阅读4分钟

第一种方式:继承Thread类,覆写run()方法

1、创建一个MyThread类,继承Thread类; 2、覆写run()方法,在run()方法内编写任务代码; 3、创建MyThread类,需要注意的是,如果想要给线程命名,需要在MyThread类中创建构造方法,在构造方法内调用父类Thread的有参构造 4、启动线程

/**
 * 多线程的第一种创建方式
 */
public class EssayTest01 {
    public static void main(String[] args) {
        // 创建两个继承了Thread的类对象,并启动
        MyThread t1 = new MyThread("线程1");
        MyThread t2 = new MyThread("线程2");

        // 启动线程
        t1.start();
        t2.start();
    }
}

/**
 * 创建一个类,继承Thread类,覆写run()方法
 */
class MyThread extends Thread {
    /**
     * 如果要给线程命名,这里需要调用Thread中的有参构造方法
     */
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + " 这是多线程的第一种创建方式:运行第" + (i + 1) + "次");
        }
    }
}

在这里插入图片描述

第二种方式:实现Runnable接口,实现run()方法,再创建Thread对象

1、创建一个MyRunnable类,实现Runnable接口; 2、实现run()方法,在run()方法内编写任务代码; 3、创建MyRunnable类对象 4、创建Thread线程类对象,将MyRunnable对象作为参数传入 5、启动线程

/**
 * 多线程实现方式2:实现Runnable接口
 */
public class EssayTest02 {
    public static void main(String[] args) {
        // 创建MyRunnable对象
        MyRunnable mr = new MyRunnable();

        // 创建线程对象并设置线程名,将MyRunnable对象作为参数传入
        Thread t1 = new Thread(mr, "线程1");
        Thread t2 = new Thread(mr, "线程2");

        // 启动线程
        t1.start();
        t2.start();
    }

}

/**
 * 创建一个类,实现Runnable接口,实现run()方法
 */
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + " 这是多线程的第二种创建方式:运行第" + (i + 1) + "次");
        }
    }
}

在这里插入图片描述

另外,可以使用匿名内部类+lambda表达式的方式实现,如下:

/**
 * 多线程实现方式2:实现Runnable接口,用匿名内部类+lambda表达式
 */
public class EssayTest02 {
    public static void main(String[] args) {

        // 创建线程对象并设置线程名,将MyRunnable对象作为参数传入
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                System.out.println(Thread.currentThread().getName() + " 这是多线程的第二种创建方式:运行第" + (i + 1) + "次");
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                System.out.println(Thread.currentThread().getName() + " 这是多线程的第二种创建方式:运行第" + (i + 1) + "次");
            }
        });

        // 启动线程
        t1.start();
        t2.start();
    }
}

但需要注意的是,这样就不能让两个线程对同一资源进行操作了 在这里插入图片描述

第三种方式:实现Callable接口,实现call()方法,再创建FutureTask来管理后面创建的Thread对象

1、创建一个MyCallable类,实现Callable接口; 2、实现call()方法,在call()方法内编写任务代码; 3、创建MyCallable类对象 4、创建FutureTask对象,将MyCallable对象作为传入 5、创建Thread线程对象,将FutureTask对象作为参数传入 6、启动线程

需要注意的是, (1)FutureTask泛型的类型要与call()方法的返回值,即Callable指定的泛型一致; (2)使用FutureTask对象的get()方法获取线程的返回值,要在线程启动start()方法的后面,不然程序会干瞪眼,不会输出任何结果

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

/**
 * 多线程创建方式3:实现Callable接口,实现call()方法,再创建FutureTask来管理后面创建的Thread对象
 */
public class EssayTest03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建MyCallable对象
        MyCallable mc = new MyCallable();

        // 创建FutureTask对象,将MyCallable对象作为传入传入,FutureTask对象的泛型要与Callable的一致
        FutureTask<String> ft = new FutureTask<String>(mc);

        // 创建线程,将FutureTask作为参数传入
        Thread t = new Thread(ft);

        // 启动线程
        t.start();

        // 通过get()方法获取线程的返回值,注意要放在start()后面
        System.out.println(ft.get());
    }
}

/**
 * 创建一个类,实现Callable接口,实现call()方法,注意call()方法的泛型指的是方法的返回值类型
 */
class MyCallable implements Callable<String> {

    @Override
    public String call() throws Exception {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + " 这是多线程的第三种创建方式:运行第" + (i + 1) + "次");
        }
        return "success";
    }
}

在这里插入图片描述

总结

第一种创建方式:逻辑简单,结构清晰,便于理解;但耦合高,每个对象都和MyThread直接关联,而且如果要设置线程名,还必须创建一个有参的构造方法

第二种创建方式:使用lambda表达,可以简化代码,解耦合;但如果涉及到多个线程对同一资源处理,就不能使用lambda表达式的方式了,另外线程没有返回值,无法知道线程运行结果

第三种创建方式:功能强大,可以返回线程运行的结果;但结构复杂,不易理解

首次发布

hezhongying.blog.csdn.net/article/det…