引言
在现代软件开发中,并发编程是提高系统性能和响应能力的关键技术之一。Java作为一门广泛使用的编程语言,提供了丰富的并发编程工具和API。本文将深入探讨Java并发编程的基础知识、常见问题以及实践技巧,帮助你更好地掌握并发编程的核心概念。
Java并发编程的基础
1. 线程(Thread)
线程是Java并发编程的基本单位。每个线程代表一个独立的执行路径。
创建线程的两种方式
-
继承
Thread
类class MyThread extends Thread { @Override public void run() { System.out.println("Thread is running"); } } public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 启动线程 } }
-
实现
Runnable
接口class MyRunnable implements Runnable { @Override public void run() { System.out.println("Thread is running"); } } public class Main { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); // 启动线程 } }
线程的生命周期
-
新建(New):线程被创建但未启动。
-
就绪(Runnable):线程已启动,等待CPU调度。
-
运行(Running):线程正在执行。
-
阻塞(Blocked):线程等待资源或锁。
-
终止(Terminated):线程执行完毕。
2. 同步(Synchronization)
多线程访问共享资源时,可能会导致数据不一致问题。Java提供了多种同步机制来解决这个问题。
1. synchronized
关键字
-
用于方法或代码块,确保同一时间只有一个线程访问共享资源。
-
示例:
class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } public class Main { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("Count: " + counter.getCount()); // 输出2000 } }
2. ReentrantLock
-
显式锁,比
synchronized
更灵活,支持公平锁和非公平锁。 -
示例:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Counter { private int count = 0; private Lock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { return count; } }
3. 线程间通信
Java提供了wait()
、notify()
和notifyAll()
方法来实现线程间的通信。
示例:生产者-消费者模型
class Buffer {
private int data;
private boolean available = false;
public synchronized void produce(int value) throws InterruptedException {
while (available) {
wait(); // 等待消费者消费
}
data = value;
available = true;
notifyAll(); // 通知消费者
}
public synchronized int consume() throws InterruptedException {
while (!available) {
wait(); // 等待生产者生产
}
available = false;
notifyAll(); // 通知生产者
return data;
}
}
public class Main {
public static void main(String[] args) {
Buffer buffer = new Buffer();
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
buffer.produce(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
int value = buffer.consume();
System.out.println("Consumed: " + value);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
Java并发工具类
1. Executor
框架
-
用于管理线程池,避免频繁创建和销毁线程。
-
示例:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(() -> System.out.println("Task 1")); executor.submit(() -> System.out.println("Task 2")); executor.shutdown(); } }
2. Future
和Callable
-
Callable
用于返回结果的线程任务,Future
用于获取结果。 -
示例:
import java.util.concurrent.*; public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(() -> { Thread.sleep(1000); return 42; }); System.out.println("Result: " + future.get()); // 输出42 executor.shutdown(); } }
3. Concurrent Collections
-
线程安全的集合类,如
ConcurrentHashMap
、CopyOnWriteArrayList
等。 -
示例:
import java.util.concurrent.ConcurrentHashMap; public class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("key1", 1); map.put("key2", 2); System.out.println(map.get("key1")); // 输出1 } }
常见问题与解决方案
1. 死锁
-
解决方案:避免嵌套锁、使用超时机制(如
tryLock
)。
2. 竞态条件
-
解决方案:使用同步机制(如
synchronized
、ReentrantLock
)。
3. 线程饥饿
-
解决方案:使用公平锁或调整线程优先级。
总结
Java并发编程是提高系统性能的重要手段,但也伴随着复杂性。通过掌握线程、同步机制、线程间通信以及并发工具类,你可以编写出高效且安全的并发程序。希望本文能帮助你更好地理解Java并发编程的核心概念和实践技巧!