我是靠谱客的博主 刻苦太阳,最近开发中收集的这篇文章主要介绍8种创建线程的方式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

8种创建线程的方式

总结:

继承Thread、实现Runnable、Callble接口都没有离开Thread类

TimerTask本质上也是实现Runnable接口

有些都是前3种的变体

  1. 继承Thread类,重写run方法

本质是Runnable即Thread实现Runnable接口

public class NO3CreateThread01 extends Thread{

    @Override

    public void run() {

        super.run();

        System.out.println(Thread.currentThread().getName());

    }

    public static void main(String[] args) {

        System.out.println("main方法的线程名:"+ Thread.currentThread().getName());

        new NO3CreateThread01().start();

    }

}

2.实现Runnable接口,重写run方法

public class NO3CreateThread02 implements Runnable {

    @Override

    public void run() {

        System.out.println(Thread.currentThread().getName());

    }

    public static void main(String[] args) {

        new Thread( new NO3CreateThread02()).start();

    }

}

3.实现Callable接口,创建带返回值的线程,也就是传说的异步经常用的方式

本质是使用使用Callable、FutureTask、Thread一起创建线程

public class NO3CreateThread03 implements Callable<String> { //利用泛型指定返回值类型

    @Override

    public String call() throws Exception {

        System.out.println(Thread.currentThread().getName());

        TimeUnit.SECONDS.sleep(30);

        return "allen create a thread";

    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        FutureTask<String> futureTask = new FutureTask<>(new NO3CreateThread03()); //此处泛型必须和Callable的一样

        new Thread(futureTask).start();

        String result = futureTask.get(); //此处会阻塞一直到futureTask拿到"allen create a thread"

        System.out.println(result);

    }

}

启动方式都是:

1. new Thread(Thread的子类或Runnable接口的实现类或FutureTask)

规范:创建线程,必须指定线程名,便于日志分析

4. 匿名内部类的方式

本质上是继承Thread、实现Runnable接口的变体

适用于:创建启动线程次数少的环境,书写更简洁

4.1>作为Thread的子类但没有类名并处于NO3CreateThread04类中顾命名”匿名内部类”

new Thread() {

    @Override

    public void run() {

        System.out.println("匿名内部类创建线程方式1...");

    }

}.start();

4.2>实现Runnable接口,但没有类名,又处于NO3CreateThread04类种,顾命名”匿名内部类“

new Thread(new Runnable() {

    @Override

    public void run() {

        System.out.println("匿名内部类创建线程方式2...");

    }

} ).start();

4.3>是方式2的变体,因为Runnable是函数式接口,可以使用lambda方式

new Thread(() -> System.out.println("匿名内部类+lambda创建线程方式3...")).start();

5.JDK8的并行流parallelSteam

import java.util.Arrays;
import java.util.List;

public class Thread05 {
    public static void main(String[] args) {
        List<Integer> ints = Arrays.asList(1, 2, 5, 3, 6, 4);
        Thread05 thread05 = new Thread05();
        System.out.println("总和:" + thread05.add(ints));

    }
    public int add(List<Integer> ints){
        // 若Lambda是串行执行,则应顺序打印
        ints.stream().forEach(System.out::print);
        System.out.println();
        // /Lambda有stream和parallelSteam(并行)
        ints.parallelStream().forEach(System.out::print);
        System.out.println();
        return ints.parallelStream().mapToInt(i->i).sum();
    }
}

6.定时器-java.util.Timer&TimerTask

此方式使用要求不高且线程少的场景,如果可以修改执行频率建议使用quartz

Timer timer = new Timer();

        timer.schedule(new TimerTask() {

            @Override

            public void run() {

                System.out.println("定时任务延迟0(即立刻执行),每隔2000ms执行一次" + Thread.currentThread().getName());

            }

        }, 0, 2000);

ps:定时器quartz,会有一个专题讲解

7.使用线程池创建线程Executors、ExecutorService或ThreadPoolExecutor

ExecutorService,而ExecutorService是Executor的子接口

//创建带有5个线程的线程池

//Executor threadPool = Executors.newFixedThreadPool(5);

// 手动创建线程池,建议使用ThreadPoolExecutor类

ExecutorService threadPool = Executors.newFixedThreadPool(5);

for(int i = 0; i < 10; i++){

    threadPool.execute(new Runnable() {

        @Override

        public void run() {

            System.out.println(Thread.currentThread().getName()+" is running");

        }

    });

}

//如果需要关闭线程池必须使用ExecutorService

threadPool.shutdown();

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 自定义线程池
 */
public class Thread0702 {
    public static void main(String[] args) {

        // 缓存队列设置固定长度为2, 为了快速触发 rejectHandler
        BlockingDeque<Runnable> blockingDeque = new LinkedBlockingDeque<>(2);

        // 假设外部任务线程的来源由机房1 和 机房2的混合调用
        UserThreadFactory f1 = new UserThreadFactory(" 第 1 机房 ");
        UserThreadFactory f2 = new UserThreadFactory(" 第 2 机房 ");

        UserRejectHandler handler = new UserRejectHandler();

        // 核心线程为1, 最大线程为2, 为了保证触发 rejectHandler
        ThreadPoolExecutor threadPoolFirst = new ThreadPoolExecutor(1, 2,
                60, TimeUnit.SECONDS, blockingDeque, f1, handler);

        // 利用第二个线程工厂实例创建第二个线程池
        ThreadPoolExecutor threadPoolSecond = new ThreadPoolExecutor(1, 2,
                60, TimeUnit.SECONDS, blockingDeque, f2, handler);

        // 创建 400 个任务线程
        Runnable task = new Task();
        for (int i = 0; i < 200; ++i) {
            threadPoolFirst.execute(task);
            threadPoolSecond.execute(task);
        }

    }
}

/**
 * 自定义线程池
 */
 class UserThreadFactory implements ThreadFactory {

    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    // 定义线程组名称,在使用 jstack 来排查线程问题时,非常有帮助
    UserThreadFactory(String whatFeatureOfGroup) {

        this.namePrefix = "UserThreadFactory's " + whatFeatureOfGroup + "-Worker-";
    }

    public Thread newThread(Runnable runnable) {

        String name = this.namePrefix + nextId.getAndIncrement();
        Thread thread = new Thread(null, runnable, name, 0);
        System.out.println(thread.getName());
        return thread;
    }
}

// 任务执行体
class Task implements Runnable {

    private final AtomicLong count = new AtomicLong(0L);

    public void run() {

        System.out.println("running_" + count.getAndIncrement());
    }
}


/**
 * 拒绝策略
 */
 class UserRejectHandler implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {

        System.out.println("task rejected. " + threadPoolExecutor.toString());
    }
}

8.使用spring自带异步创建线程:@Async

本质上也是线程池

以springboot项目为例:

@Service

public class NO3CreateThread08 {

    @Async

    public void AsyncA() {

        System.out.println("Async_A is running,name:" + Thread.currentThread().getName());

    }

    @Async

    public void AsyncB() {

        System.out.println("Async_B is running,name:" + Thread.currentThread().getName());

    }

}

测试:

@EnableAsync

@SpringBootApplication

public class ThreadApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(ThreadApplication.class, args);

        NO3CreateThread08 demo08 = context.getBean(NO3CreateThread08.class);

        demo08.AsyncA();

        demo08.AsyncB();

    }

}

最后

以上就是刻苦太阳为你收集整理的8种创建线程的方式的全部内容,希望文章能够帮你解决8种创建线程的方式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部