java创建线程的几种方式
多线程技术是我们后端工程师在面试的时候必问的一个知识点,上一篇写了线程的生命周期及几个状态的转换,这篇来盘点一下创建线程的几种方式,这个也是一个高频面试点。
创建线程有四种基本的方式:
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口
4、创建线程池
下面来详细的演示每种方式是如何创建的:
1、继承Tread类
方法:定义一个继承Thread类的子类,重写run()方法,run()方法的方法体就是线程需要执行的任务。创建子类实例,调用start()来启动线程。
//定义thread类的子类,重写run方法
class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程执行体开始执行喽~");
}
@Test
public void thread1(){
//创建子类实例,调用start()来启动线程
MyThread thread = new MyThread();
thread.start();
}
运行单元测试结果:
方式二、实现Runnable接口
方法:1、定义一个Rannable接口的实现类,同样要重写run()方法,run()方法的方法体就是线程需要执行的任务。
2.创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread类才是真正的线程对象
3.依然是通过调用线程对象的start方法来启动线程
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("MyRunnable线程执行体开始执行喽~");
}
}
@Test
public void thread2(){
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
方式3:使用Callable和Future来创建线程
和Runnable接口类似但又不一样,Callable接口提供了一个call()方法来作为线程的执行体,call()方法比run()方法功能要更加强大,call()方法可以有返回值,也可以声明抛出异常(前两种如果要抛异常只能通过try,catch来实现)。
方法:1.新创建Callable接口的实现类,并实现call()方法。
2、然后创建该类的实例
2.使用FutureTask类来包装Callable对象。该FutureTask对象封装了Callable对象的call()方法的返回值
3.使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口并在重写的run方法中执行call方法)
4.可以通过调用FutureTask对象的get方法来获取线程执行后的返回值
这种方法虽然可以获取到返回值,但缺点是代码复杂开发成本较高
class MyCallable implements Callable<String> {
//call方法可以带有返回值,
@Override
public String call() throws Exception {
System.out.println("MyCallable线程执行体开始执行喽~");
return "hello";
}
}
@Test
public void thread3() throws ExecutionException, InterruptedException {
MyCallable callable = new MyCallable();
FutureTask<String> futureTask= new FutureTask<>(callable);
new Thread(futureTask).start();
System.out.println("返回值:"+futureTask.get());
}
运行结果:
方法4:通过线程池来创建线程
Java中提供了一个Executors的类,通过它可以直接帮我们创建常用的线程池,比如:
Executors.newSingleThreadExecutor() 创建容量一个线程的线程池
Executors.newFixedThreadPool(int) 创建固定大小的线程池
Executors.newCachedThreadPool() 创建一个可缓存线程池
Executors.newScheduledThreadPool() 创建一个大小无限的线程池
现在项目中大多数使用线程池来创建线程,下一篇我们再详细讲解线程池相关知识,此处简单了解即可。
@Test
public void thread4() {
//创建一个容量是10的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程池执行任务,当前线程名:"+Thread.currentThread().getName());
}
});
}
}
运行结果:
追踪线程池的源代码,其实用线程池创建线程的本质最终也是使用 new Thread(target) 方法创建的线程,只是将创建的这些线程放入一个池子中进行管理了
方式5:通过lambda的方式实现
jdk8有lamda表达式以后, 使用Lambda表达式可以更简洁地创建线程,不需要显式地创建一个新的类或实现接口。缺点就是可能会降低代码的可读性,特别是对于复杂的线程逻辑。
例如:
@Test
public void thread5() {
new Thread(()->sayHello()).start();
}
public void sayHello(){
System.out.println("say hello");
}
运行结果:
下一篇详细盘点线程池相关知识!
原文地址:https://blog.csdn.net/m15732622413/article/details/143683440
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!