Java高并发编程是现代软件开发中的关键技术,本文全面介绍了Java高并发学习的基础知识、线程管理、并发工具类以及实战案例,旨在帮助开发者理解和掌握Java高并发的核心概念和实践技巧。
Java高并发学习:从入门到实践指南 Java高并发基础知识了解并发编程的重要性
在现代软件开发中,高性能和高并发已经成为软件系统的基本要求。并发编程可以充分利用多核处理器的能力,提高程序执行效率,满足用户对响应速度的需求。此外,通过并发编程可以实现更多复杂的功能和机制,例如并行计算、实时响应等。
Java并发编程的基本概念
Java并发编程涉及多个关键概念,包括线程、进程、并发模型等。线程是程序执行的基本单位,每个程序可以包含一个或多个线程。进程则是独立的执行环境,每个进程可以包含一个或多个线程。
并发模型和并行模型
Java并发编程主要关注的是并发模型。并发模型通过在不同线程之间分配执行时间来实现,而并行模型则通过将任务分配到不同的处理器核心上来实现。Java提供了多种并发工具和API,例如java.util.concurrent
包,提供了丰富的并发编程支持。
下面是一些基本概念的代码示例:
public class BasicConcurrency {
public static void main(String[] args) {
// 创建线程
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Thread Running: " + i);
}
});
// 启动线程
thread.start();
}
}
线程与多线程
Java线程的创建和启动
Java提供了多种创建和启动线程的方法。最常见的方式是继承Thread
类或实现Runnable
接口。
继承Thread类:
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread Running: " + i);
}
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
实现Runnable接口:
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runnable Running: " + i);
}
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
线程的状态和生命周期
Java线程主要有五种状态:新建、可运行、阻塞、等待和终止。其中,线程的生命周期中会经历这些状态变化。
- 新建:线程被创建,但还没有调用
start
方法。 - 可运行:线程调用
start
方法后,进入可运行状态。此时线程可以由线程调度器调度执行。 - 阻塞:线程被阻塞,等待某些操作完成,例如I/O操作。
- 等待:线程被阻塞,等待其他线程的唤醒操作。
- 终止:线程执行完毕或异常退出。
线程同步与互斥
为了保证多个线程安全地访问共享资源,Java提供了多种同步机制。最常用的是synchronized
关键字。
synchronized关键字用于确保同一时刻只有一个线程可以访问特定代码块或方法。
public class SynchronizedExample {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public void decrement() {
synchronized (lock) {
count--;
}
}
public int getCount() {
return count;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.decrement();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + example.getCount());
}
}
Java并发工具类
synchronized关键字
synchronized
关键字可以用于方法或代码块,确保同一时刻只有一个线程可以访问该方法或代码块。
public class SynchronizedKeyword {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
public static void main(String[] args) {
SynchronizedKeyword sync = new SynchronizedKeyword();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sync.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sync.decrement();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + sync.getCount());
}
}
volatile关键字
volatile
关键字用于确保变量的可见性。当一个变量被标记为volatile
时,任何线程对该变量的修改都会立即被其他线程看到。
public class VolatileExample {
private volatile boolean ready = false;
public void producer() {
System.out.println("Producer is producing...");
ready = true;
}
public void consumer() {
while (!ready) {
// 等待变量变化
}
System.out.println("Consumer is consuming...");
}
public static void main(String[] args) {
VolatileExample ve = new VolatileExample();
Thread t1 = new Thread(ve::producer);
Thread t2 = new Thread(ve::consumer);
t1.start();
t2.start();
}
}
Lock接口及其实现类
Lock
接口提供了更灵活的锁机制,可以替代synchronized
关键字。ReentrantLock
是Lock
接口的一个常见实现。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
count--;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
public static void main(String[] args) {
ReentrantLockExample rle = new ReentrantLockExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
rle.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
rle.decrement();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + rle.getCount());
}
}
Condition接口及其实现类
Condition
接口提供了比synchronized
更细粒度的同步机制。ReentrantLock
的newCondition
方法可以创建一个Condition
对象。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean ready = false;
public void producer() {
lock.lock();
try {
System.out.println("Producer is producing...");
ready = true;
condition.signal();
} finally {
lock.unlock();
}
}
public void consumer() {
lock.lock();
try {
while (!ready) {
condition.await();
}
System.out.println("Consumer is consuming...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ConditionExample ce = new ConditionExample();
Thread t1 = new Thread(ce::producer);
Thread t2 = new Thread(ce::consumer);
t1.start();
t2.start();
}
}
高并发场景下的数据结构
同步容器
Java提供了多种线程安全的集合类,例如Vector
、Hashtable
、Collections.synchronizedList
等。
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
public class SynchronizedContainers {
private List<Integer> list = new Vector<>();
public void add(int value) {
synchronized (list) {
list.add(value);
}
}
public void addSafe(int value) {
synchronized (list) {
list.add(value);
}
}
public static void main(String[] args) {
SynchronizedContainers sync = new SynchronizedContainers();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sync.add(i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sync.add(i);
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("List size: " + sync.list.size());
}
}
非阻塞数据结构
Java提供了多种非阻塞数据结构,例如ConcurrentHashMap
、ConcurrentLinkedQueue
等。这些数据结构使用CAS(Compare and Swap)操作实现线程安全性。
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class NonBlockingContainers {
private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
private ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
public void put(String key, String value) {
map.put(key, value);
}
public void add(int value) {
queue.add(value);
}
public static void main(String[] args) {
NonBlockingContainers nb = new NonBlockingContainers();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
nb.put("key" + i, "value" + i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
nb.add(i);
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Map size: " + nb.map.size());
System.out.println("Queue size: " + nb.queue.size());
}
}
基于AQS的锁设计模式
AbstractQueuedSynchronizer
(AQS)是Java并发工具包中的一个基础类,用于构建自定义的同步机制。它可以实现复杂的数据结构,例如ReentrantLock
、Semaphore
等。
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class CustomLock extends AbstractQueuedSynchronizer {
private boolean isLocked = false;
protected boolean isHeldExclusively() {
return isLocked;
}
public void lock() {
acquire(1);
}
public void unlock() {
release(1);
}
protected final boolean tryAcquire(int arg) {
if (!isLocked) {
isLocked = true;
return true;
}
return false;
}
protected final boolean tryRelease(int arg) {
if (isLocked) {
isLocked = false;
return true;
}
return false;
}
public static void main(String[] args) {
CustomLock lock = new CustomLock();
Thread t1 = new Thread(() -> {
lock.lock();
try {
System.out.println("Locked by t1");
} finally {
lock.unlock();
}
});
Thread t2 = new Thread(() -> {
lock.lock();
try {
System.out.println("Locked by t2");
} finally {
lock.unlock();
}
});
t1.start();
t2.start();
}
}
并发编程模式
生产者消费者模式
生产者消费者模式主要用于解决生产者和消费者之间的同步问题。生产者负责生产数据,消费者负责消费数据。
import java.util.concurrent.ArrayBlockingQueue;
public class ProducerConsumer {
private final ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
public void producer(int value) {
try {
queue.put(value);
System.out.println("Produced: " + value);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void consumer() {
try {
int value = queue.take();
System.out.println("Consumed: " + value);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
pc.producer(i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
pc.consumer();
}
});
t1.start();
t2.start();
}
}
读写器模式
读写器模式主要用于解决读写操作的同步问题。读操作可以并发执行,但写操作需要独占资源。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReaderWriter {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
private int count = 0;
public void read() {
readLock.lock();
try {
System.out.println("Read: " + count);
} finally {
readLock.unlock();
}
}
public void write(int value) {
writeLock.lock();
try {
count = value;
System.out.println("Write: " + value);
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
ReaderWriter rw = new ReaderWriter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
rw.read();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
rw.write(i);
}
});
t1.start();
t2.start();
}
}
信号量与屏障
信号量用于实现有限资源的访问控制,屏障用于实现多线程的同步。
import java.util.concurrent.BoundedSemaphore;
import java.util.concurrent.CountDownLatch;
public class SemaphoreBarrier {
private final BoundedSemaphore semaphore = new BoundedSemaphore(3);
private final CountDownLatch barrier = new CountDownLatch(3);
public void acquire() {
try {
semaphore.acquire();
System.out.println("Acquired semaphore");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void release() {
semaphore.release();
System.out.println("Released semaphore");
barrier.countDown();
}
public void await() {
try {
barrier.await();
System.out.println("Barrier reached");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SemaphoreBarrier sb = new SemaphoreBarrier();
Thread t1 = new Thread(sb::acquire);
Thread t2 = new Thread(sb::acquire);
Thread t3 = new Thread(sb::acquire);
Thread t4 = new Thread(sb::release);
Thread t5 = new Thread(sb::release);
Thread t6 = new Thread(sb::release);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
sb.await();
}
}
资源池模式
资源池模式主要用于管理有限资源的分配和回收。典型的例子是数据库连接池。
import java.util.concurrent.ConcurrentLinkedQueue;
public class ResourcePool {
private final ConcurrentLinkedQueue<Object> pool = new ConcurrentLinkedQueue<>();
public void add(Object resource) {
pool.add(resource);
}
public Object borrow() {
return pool.poll();
}
public static void main(String[] args) {
ResourcePool rp = new ResourcePool();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
rp.add(new Object());
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
Object resource = rp.borrow();
if (resource != null) {
System.out.println("Borrowed: " + resource);
}
}
});
t1.start();
t2.start();
}
}
实战案例
简单模拟高并发环境
模拟高并发环境可以使用JMeter或编写自定义的多线程代码。下面是一个简单的高并发环境模拟示例。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class HighConcurrencySimulation {
private final int threads = 100;
private final int iterations = 1000;
public void simulate() {
ExecutorService executor = Executors.newFixedThreadPool(threads);
for (int i = 0; i < threads; i++) {
executor.execute(() -> {
for (int j = 0; j < iterations; j++) {
// 模拟并发操作
System.out.println("Thread: " + Thread.currentThread().getName() + ", Iteration: " + j);
}
});
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
HighConcurrencySimulation hcs = new HighConcurrencySimulation();
hcs.simulate();
}
}
实战案例分析与优化
在实际应用中,需要对并发代码进行性能分析和优化。例如,可以使用JProfiler或VisualVM等工具进行性能分析,找出瓶颈并进行优化。
性能分析工具
- JProfiler: 提供详细的CPU和内存分析,帮助找到性能瓶颈。
- VisualVM: 集成了Java虚拟机监控工具,可以分析内存、线程等。
性能优化技巧
- 减少锁的竞争:通过减少锁的范围或使用更细粒度的锁,减少锁的竞争。
- 使用非阻塞数据结构:替换使用
Vector
和Hashtable
等阻塞集合。 - 减少同步开销:减少同步代码块的范围,减少不必要的同步操作。
性能调优技巧
性能调优是并发编程中非常重要的一部分。常见的优化技巧包括:
- 减少锁的持有时间:锁的持有时间越长,竞争越激烈,性能越差。
- 使用无锁数据结构:例如使用
ConcurrentHashMap
代替Hashtable
。 - 减少线程切换开销:合理设置线程池大小,避免过多线程切换。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PerformanceTuning {
private final int threads = 20;
private final int iterations = 100;
public void simulate() {
ExecutorService executor = Executors.newFixedThreadPool(threads);
for (int i = 0; i < threads; i++) {
executor.execute(() -> {
for (int j = 0; j < iterations; j++) {
// 模拟高并发操作
System.out.println("Thread: " + Thread.currentThread().getName() + ", Iteration: " + j);
}
});
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
PerformanceTuning pt = new PerformanceTuning();
pt.simulate();
}
}
总结
通过本文的学习,你已经掌握了Java高并发编程的基本概念和实践技巧。并发编程是一个广泛的领域,涉及到多线程、锁、同步、数据结构等多个方面。希望本文的内容可以帮助你在实际项目中更好地利用Java的并发编程能力,提高系统的性能和稳定性。