一、继承Thread类
实现步骤:
1.继承Thread类
2.重写run()方法
3.创建线程对象并调用start()方法
示例:
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(500); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start(); // 启动线程1
t2.start(); // 启动线程2
System.out.println("主线程继续执行...");
}
}
注意事项:
- 直接调用run() 方法是普通方法调用,不会启动新线程
- 一个线程对象只能start()一次
二、实现Runnable接口
实现步骤:
1.实现Runnable接口
2.实现run方法
3.创建Thread对象 并传入Runnable实例
4.调用start()方法
示例:
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable, "线程A");
Thread t2 = new Thread(runnable, "线程B");
t1.start();
t2.start();
}
}
优势:
- 避免单继承限制
- 适合多个线程共享相同代码
- 更符合面向对象设计思想
三、实现Callable接口(带返回值)
步骤:
1.实现Callable接口
2.实现call()方法
3.创建FutureTask对象包装Callable
4.创建Thread对象并传入FutureTask
5.调用start()方法
6.通过FutureTask.get()获取返回值
import java.util.concurrent.*;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
Thread.sleep(10);
}
return sum;
}
}
public class CallableExample {
public static void main(String[] args) throws Exception {
MyCallable callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t = new Thread(futureTask);
t.start();
// 主线程继续做其他工作
System.out.println("主线程正在计算其他内容...");
// 获取子线程计算结果(会阻塞直到计算完成)
int result = futureTask.get();
System.out.println("计算结果: " + result);
}
}
特点:
- 可以获取线程执行结果
- call()方法可以抛出异常
- 支持泛型返回值
四、使用线程池(推荐方式)
实现步骤:
1.创建线程池
2.提交任务(Runnable/Callable)
3.关闭线程池
import java.util.concurrent.*;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交10个任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println(Thread.currentThread().getName()
+ " 正在执行任务 " + taskId);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 关闭线程池
executor.shutdown();
try {
// 等待所有任务完成
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
线程池优势:
1.降低资源消耗:复用已创建的线程。
2.提高响应速度:任务到达时线程已存在
3.提高线程可管理性:统一分配、调优和监控
4.防止资源耗尽:通过限制线程数量
5.多线程编程注意事项
1.线程安全:注意共享资源的同步访问
2.避免死锁:按固定顺序获取多个锁
3.性能考量:线程创建和上下文切换有开销
4.资源释放:确保finally块中释放锁和IO资源
5.异常处理:子线程异常需特殊处理(可设置UncaughtExceptionHandler)