Java 并发编程的核心是 多线程协作、共享资源同步、线程池管理 等,以下是覆盖核心场景的代码示例,包含注释和场景说明,适合学习和实际参考:
一、基础场景:创建线程(3种常用方式)
1. 继承 Thread 类
// 场景:简单独立任务,无返回值
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(100); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.setName("Thread-1");
thread2.setName("Thread-2");
thread1.start(); // 启动线程(调用 run() 方法)
thread2.start();
}
}
2. 实现 Runnable 接口(推荐,解耦线程与任务)
// 场景:多线程共享同一个任务实例(无返回值)
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// 共享任务实例
MyRunnable task = new MyRunnable();
// 线程池(推荐替代直接 new Thread)
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(new Thread(task, "Runnable-1"));
executor.submit(new Thread(task, "Runnable-2"));
executor.shutdown(); // 关闭线程池(等待任务执行完)
}
}
3. 实现 Callable 接口(有返回值,支持异常抛出)
// 场景:需要获取线程执行结果(如计算任务)
class MyCallable implements Callable<Integer> {
private int num;
public MyCallable(int num) {
this.num = num;
}
// 有返回值,可抛出异常
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= num; i++) {
sum += i;
Thread.sleep(50);
}
System.out.println(Thread.currentThread().getName() + " 计算完成");
return sum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交任务,返回 Future 对象(用于获取结果)
Future<Integer> future1 = executor.submit(new MyCallable(10));
Future<Integer> future2 = executor.submit(new MyCallable(20));
// 获取结果(阻塞等待线程执行完)
System.out.println("Callable-1 结果:" + future1.get());
System.out.println("Callable-2 结果:" + future2.get());
executor.shutdown();
}
}
二、核心场景:共享资源同步(解决线程安全问题)
1. synchronized 关键字(锁方法/代码块)
// 场景:多线程操作共享变量(如计数器),避免并发修改异常
class Counter {
private int count = 0;
// 方式1:锁整个方法
public synchronized void increment() {
count++;
}
// 方式2:锁代码块(更灵活,锁粒度更小)
public void decrement() {
synchronized (this) { // 锁对象(通常是当前实例或类对象)
count--;
}
}
public int getCount() {
return count;
}
}
public class SynchronizedDemo {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
ExecutorService executor = Executors.newFixedThreadPool(10);
// 10个线程同时执行 increment,共执行1000次
for (int i = 0; i < 1000; i++) {
executor.submit(counter::increment);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.SECONDS); // 等待所有线程执行完
System.out.println("最终计数:" + counter.getCount()); // 正确结果:1000(无同步会小于1000)
}
}
2. ReentrantLock(可重入锁,比 synchronized 更灵活)
// 场景:需要手动控制锁的获取/释放,支持公平锁、条件变量等
class ReentrantLockCounter {
private int count = 0;
// 可重入锁(参数 true 表示公平锁,按线程等待顺序获取锁)
private final Lock lock = new ReentrantLock(true);
public void increment() {
lock.lock(); // 获取锁(未获取到则阻塞)
try {
count++; // 临界区(共享资源操作)
} finally {
lock.unlock(); // 必须在 finally 中释放锁,避免死锁
}
}
public int getCount() {
return count;
}
}
public class ReentrantLockDemo {
public static void main(String[] args) throws InterruptedException {
ReentrantLockCounter counter = new ReentrantLockCounter();
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
executor.submit(counter::increment);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("最终计数:" + counter.getCount()); // 1000
}
}
3. 原子类(无锁同步,基于 CAS 机制)
// 场景:简单的数值增减,无需锁,性能更高
public class AtomicDemo {
public static void main(String[] args) throws InterruptedException {
// 原子整数(线程安全的自增/自减)
AtomicInteger atomicCount = new AtomicInteger(0);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
// incrementAndGet():原子自增并返回新值
executor.submit(atomicCount::incrementAndGet);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("最终计数:" + atomicCount.get()); // 1000
}
}
三、高级场景:线程协作(等待/通知机制)
1. Condition 条件变量(配合 ReentrantLock)
// 场景:生产者-消费者模型(线程间协作,避免忙等)
class MessageQueue {
private final Queue<String> queue = new LinkedList<>();
private final Lock lock = new ReentrantLock();
// 条件变量:队列非空(消费者等待)、队列未满(生产者等待)
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();
private final int capacity = 5; // 队列最大容量
// 生产者放入消息
public void put(String message) throws InterruptedException {
lock.lock();
try {
// 队列满了,生产者等待
while (queue.size() == capacity) {
notFull.await(); // 释放锁,进入等待队列
}
queue.offer(message);
System.out.println("生产者放入:" + message);
notEmpty.signal(); // 通知消费者:队列非空了
} finally {
lock.unlock();
}
}
// 消费者取出消息
public String take() throws InterruptedException {
lock.lock();
try {
// 队列为空,消费者等待
while (queue.isEmpty()) {
notEmpty.await();
}
String message = queue.poll();
System.out.println("消费者取出:" + message);
notFull.signal(); // 通知生产者:队列未满了
return message;
} finally {
lock.unlock();
}
}
}
public class ConditionDemo {
public static void main(String[] args) {
MessageQueue queue = new MessageQueue();
ExecutorService executor = Executors.newFixedThreadPool(4);
// 2个生产者
executor.submit(() -> {
try {
queue.put("消息1");
queue.put("消息2");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executor.submit(() -> {
try {
queue.put("消息3");
queue.put("消息4");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 2个消费者
executor.submit(() -> {
try {
queue.take();
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executor.submit(() -> {
try {
queue.take();
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executor.shutdown();
}
}
2. CountDownLatch(线程等待多任务完成)
// 场景:主线程等待所有子线程执行完再继续(如并行计算汇总结果)
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int threadNum = 3;
// 计数器初始值 = 线程数
CountDownLatch latch = new CountDownLatch(threadNum);
ExecutorService executor = Executors.newFixedThreadPool(threadNum);
for (int i = 0; i < threadNum; i++) {
int taskId = i;
executor.submit(() -> {
try {
System.out.println("任务" + taskId + "执行中...");
Thread.sleep(1000);
System.out.println("任务" + taskId + "执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown(); // 计数器减1
}
});
}
System.out.println("主线程等待所有任务完成...");
latch.await(); // 主线程阻塞,直到计数器为0
System.out.println("所有任务完成,主线程继续执行");
executor.shutdown();
}
}
四、线程池(推荐:控制线程数量,避免资源耗尽)
Java 推荐用 ThreadPoolExecutor 自定义线程池(避免 Executors 工具类的默认缺陷):
public class ThreadPoolDemo {
public static void main(String[] args) {
// 核心参数说明:
// 1. 核心线程数(常驻线程):2
// 2. 最大线程数:5
// 3. 空闲线程存活时间:60秒(超过核心线程数的线程,空闲60秒后销毁)
// 4. 时间单位:秒
// 5. 任务队列(阻塞队列):容量10(超出核心线程数的任务先入队)
// 6. 线程工厂(创建线程的方式):默认
// 7. 拒绝策略(队列满+最大线程数满时,如何处理新任务):抛异常
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
5,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
// 提交15个任务(核心2 + 队列10 + 最大3 = 15,刚好不触发拒绝策略)
for (int i = 0; i < 15; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("线程" + Thread.currentThread().getId() + "执行任务" + taskId);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown(); // 平缓关闭:等待已提交的任务执行完,不再接收新任务
// executor.shutdownNow(); // 强制关闭:立即中断正在执行的任务,返回未执行的任务
}
}
关键说明:
- 线程安全:共享资源必须通过
synchronized、Lock、原子类等方式同步,否则会出现ConcurrentModificationException或数据不一致; - 线程池:避免直接
new Thread(),线程池可复用线程、控制并发数,降低资源开销; - 协作机制:
Condition、CountDownLatch、CyclicBarrier等工具类可实现复杂的线程协作,比wait()/notify()更灵活; - 异常处理:线程中未捕获的异常会导致线程终止,建议在
run()/call()中统一捕获异常。
1302

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



