JAVA面试——创建线程有几种方法?
1.继承Thread类:创建一个类,继承自 Thread 类,并重写 run() 方法来定义线程的执行逻辑。然后可以实例化这个类并调用 start() 方法来启动线程。
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行逻辑
for (int i = 0; i < 5; i++) {
System.out.println("当前线程: " + Thread.currentThread().getName() + ",i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
在这个例子中,MyThread 类继承了 Thread 类,并重写了 run() 方法来定义线程的执行逻辑,这里简单地打印输出一些信息并暂停 1 秒。在 main 方法中,我们实例化了 MyThread 类并调用 start() 方法来启动线程。
继承 Thread 类的方式相对简单直接,但也存在一些局限性,因为 Java 不支持多重继承,所以继承了 Thread 类之后就无法再继承其他类。另外,如果想要共享实例变量,也不太方便。
总结起来,继承 Thread 类是一种简单直接的创建线程的方式,适合一些简单的线程逻辑,但在复杂的场景中可能需要考虑其他方式。
2.实现Runnable接口:创建一个类,实现 Runnable 接口,并实现 run() 方法来定义线程的执行逻辑。然后可以将这个类的实例传递给 Thread 类的构造函数来创建线程。
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行逻辑
for (int i = 0; i < 5; i++) {
System.out.println("当前线程: " + Thread.currentThread().getName() + ",i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
在这个例子中,MyRunnable 类实现了 Runnable 接口,并重写了 run() 方法来定义线程的执行逻辑,这里简单地打印输出一些信息并暂停 1 秒。在 main 方法中,我们创建了 MyRunnable 的实例,并将其传递给 Thread 的构造函数来创建线程。最后调用 thread.start() 来启动线程。
需要注意的是,run() 方法不会返回任何结果,没有返回值。如果需要获取线程的执行结果,可以使用 Callable 接口来代替。
总结起来,实现 Runnable 接口是一种比较常见的创建线程的方式,它不仅简单易用,而且可以方便地共享实例变量。
3.实现Callable接口:它可以让线程执行完后返回一个结果或者抛出一个异常。与 Runnable 接口不同的是,Callable 接口中的 call() 方法可以声明抛出异常,并且可以有返回值。
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}
}
public class Main {
public static void main(String[] args) throws Exception {
Callable<Integer> myCallable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println("计算结果:" + futureTask.get());
}
}
在这个例子中,MyCallable 类实现了 Callable 接口,并实现了 call() 方法来定义线程的执行逻辑,这里是计算 1-100 的和并返回。在 main 方法中,我们将 MyCallable 实例传递给 FutureTask 的构造函数,再将 FutureTask 实例传递给 Thread 的构造函数来创建线程并启动执行。最后调用 futureTask.get() 方法来获取线程的返回结果。
需要注意的是,call() 方法可以声明抛出异常,并且可以有返回值。同时,在本例中,我们使用了 FutureTask 来获取线程执行结果,它是一个包装器,可以将 Callable 转换成 Future。
总之,实现 Callable 接口可以让我们更方便地同时获取线程的返回结果和异常信息,提高了代码的可靠性和可读性。
4.使用线程池的方式创建线程:使用线程池可以更好地管理和复用线程资源,从而提高程序的性能和效率。Java 提供了 Executor 框架来创建和管理线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
// 创建线程池,指定线程数为 5
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交任务给线程池
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("任务 " + (i + 1));
executor.execute(worker);
}
// 关闭线程池
executor.shutdown();
}
}
class WorkerThread implements Runnable {
private String taskName;
public WorkerThread(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 开始执行任务:" + taskName);
try {
// 模拟任务执行时间
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 完成任务:" + taskName);
}
}
在这个例子中,我们通过
Executors.newFixedThreadPool(5)
创建了一个固定大小为 5 的线程池。然后我们提交了 10 个任务给线程池,每个任务都是一个实现了 Runnable 接口的 WorkerThread 类。每个任务会被线程池中的一个线程执行。最后,我们调用
executor.shutdown()
关闭线程池。这会等待所有已提交的任务执行完毕,并且不再接受新的任务。使用线程池可以有效地管理线程的创建和销毁,避免了频繁创建和销毁线程的开销。此外,线程池还提供了一些额外的功能,例如线程调度、线程超时等,能更好地控制线程的执行。
总结起来,使用线程池能够更好地管理和复用线程资源,提高程序的性能和效率。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!