概述
8种创建线程的方式
总结:
继承Thread、实现Runnable、Callble接口都没有离开Thread类
TimerTask本质上也是实现Runnable接口
有些都是前3种的变体
- 继承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种创建线程的方式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复