【Java多线程】告别线程混乱!深度解析Java多线程4大实现方式(附实战案例)

时间:2025-04-14 07:29:26

一、继承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)