Java 学习系列(9):Java 并发编程详解
1. 并发编程概述
并发编程是指程序在同一时间段内可以处理多个任务。Java 提供了强大的并发编程支持,能够充分利用多核处理器,提升程序性能。并发编程的核心问题是如何正确地处理多个线程同时执行时可能遇到的资源竞争和数据一致性问题。
Java 提供了多种方式来实现并发,如使用线程、Executor 框架、并发工具类等。
2. 线程的基本概念
在 Java 中,线程是程序执行的最小单元。每个 Java 程序至少有一个主线程,在启动时由 JVM 自动创建。多线程可以同时执行多个任务。
2.1 创建线程的方式
2.1.1 继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
2.1.2 实现 Runnable 接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable is running");
}
}
public class RunnableExample {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // 启动线程
}
}
2.2 线程生命周期
线程的生命周期通常包括以下状态:
- 新建(New):线程被创建但未启动。
- 就绪(Runnable):线程已准备好执行,但等待 CPU 时间片。
- 运行中(Running):线程正在执行任务。
- 阻塞(Blocked):线程等待某个资源(如文件或锁)释放。
- 死亡(Dead):线程执行完毕或者被强制终止。
3. 线程同步
当多个线程访问共享资源时,可能会发生竞争条件,从而导致数据不一致。为了解决这个问题,Java 提供了多种同步机制。
3.1 synchronized 关键字
synchronized 是最常用的同步机制,它可以用于方法或代码块中,确保同一时刻只有一个线程能够访问该代码。
3.1.1 同步方法
class Counter {
private int count = 0;
// 同步方法,保证线程安全
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizedExample {
public static void main(String[] args) {
Counter counter = new Counter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
}
}
3.1.2 同步代码块
class Counter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
3.2 ReentrantLock 类
除了 synchronized,Java 还提供了显式的锁机制,ReentrantLock 类是 java.util.concurrent 包中提供的一个锁。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock(); // 获取锁
try {
count++;
} finally {
lock.unlock(); // 释放锁
}
}
public int getCount() {
return count;
}
}
4. 线程池
线程池是一个用于管理和复用线程的机制,可以避免频繁创建和销毁线程的开销。Java 提供了 Executor 框架来简化线程池的使用。
4.1 使用 ExecutorService
import java.util.concurrent.*;
public class ExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable task = () -> {
System.out.println(Thread.currentThread().getName() + " is executing task");
};
executor.submit(task);
executor.submit(task);
executor.shutdown(); // 关闭线程池
}
}
4.2 常见的线程池类型
- FixedThreadPool:固定大小的线程池。
- CachedThreadPool:根据需要创建新的线程,若线程空闲超过一定时间,则会被销毁。
- SingleThreadExecutor:只有一个线程的线程池。
- ScheduledThreadPool:可以定时执行任务的线程池。
ExecutorService executor = Executors.newScheduledThreadPool(2);
5. 高级并发工具类
Java 提供了一些用于处理并发问题的高级工具类,这些类位于 java.util.concurrent 包中。
5.1 CountDownLatch
CountDownLatch 是一种同步辅助工具类,它允许一个或多个线程等待,直到其他线程完成一组操作。
import java.util.concurrent.*;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
Runnable task = () -> {
try {
System.out.println(Thread.currentThread().getName() + " is doing work");
Thread.sleep(1000);
latch.countDown(); // 每个任务完成时,计数器减1
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
latch.await(); // 等待所有线程执行完毕
System.out.println("All tasks are finished");
}
}
5.2 CyclicBarrier
CyclicBarrier 用于让一组线程等待彼此完成,直到所有线程都到达某个屏障点。
import java.util.concurrent.*;
public class CyclicBarrierExample {
public static void main(String[] args) throws InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All threads reached the barrier"));
Runnable task = () -> {
try {
System.out.println(Thread.currentThread().getName() + " is working");
Thread.sleep(1000);
barrier.await(); // 等待其他线程到达屏障
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
}
6. 总结
- Java 提供了强大的并发编程支持,使用线程池和高效的同步工具可以帮助我们更好地管理和控制多线程。
synchronized和ReentrantLock是常用的线程同步工具,适用于不同的场景。ExecutorService提供了高效的线程管理方式,避免了频繁创建和销毁线程的开销。- 高级工具类如
CountDownLatch和CyclicBarrier帮助我们解决了更复杂的同步问题。
下一期:《Java 学习系列(10):Java 反射机制详解》
495

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



