在Java中实现多线程编程主要有三种核心方式:继承Thread类、实现Runnable接口、实现Callable接口(结合Future)。此外,还可以通过线程池(ExecutorService)更高效地管理线程。以下是详细实现方法及代码示例:
一、继承Thread类
Thread类是Java线程的基础类,通过继承它并重写run()方法定义线程执行逻辑,调用start()方法启动线程(而非直接调用run())。
// 1. 继承Thread类
class MyThread extends Thread {
// 2. 重写run()方法,定义线程执行逻辑
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// Thread.currentThread().getName()获取当前线程名称
System.out.println(Thread.currentThread().getName() + ":执行第" + i + "次");
try {
Thread.sleep(500); // 线程休眠500ms(模拟耗时操作)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
// 3. 创建线程对象
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 设置线程名称(可选)
thread1.setName("线程A");
thread2.setName("线程B");
// 4. 启动线程(调用start(),而非run())
thread1.start();
thread2.start();
}
}
输出(顺序可能不同,体现线程并发):
线程A:执行第0次
线程B:执行第0次
线程A:执行第1次
线程B:执行第1次
...
二、实现Runnable接口
Runnable是函数式接口(仅含run()方法),通过实现它定义线程逻辑,再将实例传入Thread类启动。推荐此方式,因为Java单继承,但可多实现。
// 1. 实现Runnable接口
class MyRunnable implements Runnable {
// 2. 实现run()方法
@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 RunnableDemo {
public static void main(String[] args) {
// 3. 创建Runnable实例
MyRunnable runnable = new MyRunnable();
// 4. 将Runnable传入Thread,创建线程对象
Thread thread1 = new Thread(runnable, "线程C");
Thread thread2 = new Thread(runnable, "线程D");
// 5. 启动线程
thread1.start();
thread2.start();
}
}
特点:多个线程可共享同一个Runnable实例的资源(如成员变量),适合多线程协作。
三、实现Callable接口(带返回值)
Callable接口与Runnable类似,但允许线程执行后返回结果,且可抛出受检异常。需结合Future或FutureTask获取结果。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// 1. 实现Callable接口,指定返回值类型(此处为Integer)
class MyCallable implements Callable<Integer> {
private int num;
public MyCallable(int num) {
this.num = num;
}
// 2. 实现call()方法(有返回值)
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= num; i++) {
sum += i;
}
System.out.println(Thread.currentThread().getName() + ":计算完成");
return sum; // 返回结果
}
}
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 3. 创建Callable实例
MyCallable callable = new MyCallable(100);
// 4. 用FutureTask包装Callable(FutureTask实现了Future和Runnable)
FutureTask<Integer> futureTask = new FutureTask<>(callable);
// 5. 传入Thread启动
Thread thread = new Thread(futureTask, "计算线程");
thread.start();
// 6. 调用get()获取结果(会阻塞当前线程,直到子线程执行完毕)
int result = futureTask.get();
System.out.println("1~100的和:" + result); // 输出:5050
}
}
特点:适合需要线程返回结果的场景(如异步计算)。
四、线程池(ExecutorService)
频繁创建/销毁线程会消耗资源,线程池可复用线程,提高效率。通过Executors工具类创建线程池(实际开发中推荐ThreadPoolExecutor自定义)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1. 创建固定大小的线程池(3个线程)
ExecutorService executor = Executors.newFixedThreadPool(3);
// 2. 提交任务(Runnable或Callable)
for (int i = 0; i < 5; i++) {
final int taskNum = i;
executor.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":执行任务" + taskNum);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
// 3. 关闭线程池(不再接受新任务,等待现有任务完成)
executor.shutdown();
}
}
常用线程池类型:
newFixedThreadPool(n):固定大小的线程池newCachedThreadPool():可缓存的线程池(线程数动态调整)newSingleThreadExecutor():单线程池(任务串行执行)newScheduledThreadPool(n):支持定时/周期性任务的线程池
五、线程常用方法
| 方法 | 说明 |
|---|---|
start() |
启动线程(底层调用run()) |
run() |
线程执行逻辑(需重写) |
sleep(long ms) |
让当前线程休眠指定毫秒(不会释放锁) |
join() |
等待该线程执行完毕后,再继续执行其他线程 |
yield() |
让出CPU资源,让其他线程优先执行 |
setPriority(int) |
设置线程优先级(1~10,默认5) |
isAlive() |
判断线程是否存活 |
六、线程安全问题
多线程共享资源时可能出现数据不一致,需通过同步机制解决:
synchronized关键字(同步方法/代码块)Lock接口(如ReentrantLock)
示例(synchronized解决线程安全):
class Counter {
private int count = 0;
// 同步方法:保证同一时间只有一个线程执行
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class ThreadSafety {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join(); // 等待t1完成
t2.join(); // 等待t2完成
System.out.println("最终计数:" + counter.getCount()); // 正确输出20000(无同步可能小于20000)
}
}
总结
- 简单场景:用
Thread或Runnable(推荐Runnable)。 - 需要返回值:用
Callable + Future。 - 高效管理线程:用线程池。
- 多线程共享资源:需考虑线程安全(
synchronized或Lock)。
多线程编程的核心是并发协作与资源同步,实际开发中需根据场景选择合适的实现方式。