Java线程简介
Java线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。每个线程都有自己独立的执行路径,但共享进程的内存空间和其他资源。Java通过java.lang.Thread类来支持多线程编程。
创建线程的几种方式
- 继承Thread类
通过继承Thread类来创建线程是最基本的一种方式。需要创建一个继承自Thread类的子类,并重写其run方法。然后创建该子类的实例,调用其start方法来启动线程。
class MyThread extends Thread {
public void run() {
System.out.println("线程运行中");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // 启动线程
}
}
- 实现Runnable接口
实现Runnable接口是另一种创建线程的方式。你需要创建一个实现了Runnable接口的类的实例,此类的实例作为Thread对象的创建参数。然后,通过调用Thread类的start方法来启动线程。
class MyRunnable implements Runnable {
public void run() {
System.out.println("线程运行中");
}
}
public class RunnableExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start(); // 启动线程
}
}
- 实现Callable接口
首先,我们定义一个实现了Callable接口的类或者匿名类。Callable接口类似于Runnable,但它允许任务完成时返回一个结果,并且可以抛出一个异常。
3.1 通过创建对象
import java.util.concurrent.Callable;
public class MyCallableTask implements Callable<String> {
@Override
public String call() throws Exception {
// 模拟耗时任务
Thread.sleep(1000);
return "任务完成,返回结果";
}
}
3.2 直接使用匿名类:
Callable<String> task = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "任务完成,返回结果";
}
};
3.3 使用Lambda表达式
Callable<String> task = () -> {
Thread.sleep(1000);
return "任务完成,返回结果";
};
3.4 使用ExecutorService执行Callable
import java.util.concurrent.*;
public class CallableExecutorExample {
public static void main(String[] args) {
// 创建一个ExecutorService
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交Callable任务到ExecutorService
Future<String> future = executor.submit(new MyCallableTask());
try {
// 等待Callable任务完成并获取结果
String result = future.get(); // 这会阻塞,直到任务完成
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// 关闭ExecutorService
executor.shutdown();
}
}
如果你使用的是匿名类或Lambda表达式定义的Callable,那么submit方法的调用方式会略有不同,但基本思路是一样的。
3.5 使用Lambda表达式的完整示例:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {
Thread.sleep(1000);
return "任务完成,返回结果";
});
try {
String result = future.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
4.使用Callable和Future(通过ExecutorService)
import java.util.concurrent.*;
class MyCallable implements Callable<Integer> {
public Integer call() throws Exception {
return 123;
}
}
public class CallableExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> future = executor.submit(new MyCallable());
System.out.println(future.get()); // 获取结果
executor.shutdown();
}
}
线程的状态
Java线程的状态主要包括以下几种:
- 新建(NEW):创建后尚未启动的线程状态。
- 运行(RUNNABLE):线程正在Java虚拟机中执行,可能正在等待其他资源(如I/O操作),但仍是运行状态。
- 阻塞(BLOCKED):线程被阻塞并等待某个监视器锁,以便进入一个同步块/方法。
- 等待(WAITING):线程无限期等待另一个线程执行特定操作(如通过Object.wait()方法等待)。
- 计时等待(TIMED_WAITING):线程等待一段时间,如调用Thread.sleep(long millis),或等待某个操作的完成(带超时时间)。
- 终止(TERMINATED):线程已执行完毕。
优缺点及区别
- 继承Thread类 vs 实现Runnable接口
- 继承Thread类:
- 优点:编写简单,可以直接使用Thread类的方法。
- 缺点:Java不支持多重继承,因此继承Thread类后不能再继承其他类。
- 实现Runnable接口:
- 优点:保持了类的灵活性,因为Java实现了单继承但支持多重接口。适用于资源共享的场景。
- 缺点:相对复杂,需要通过Thread类来创建线程。
- 使用Callable和Future
- 优点:可以返回执行结果,支持异常处理。
- 缺点:代码编写稍微复杂,需要处理Future和ExecutorService。

1万+

被折叠的 条评论
为什么被折叠?



