线程同步是多线程编程中非常重要的一部分,用于确保多个线程之间正确地访问和修改共享资源。在实现线程同步时,需要注意以下几个方面:
线程同步需要注意的事项
-
避免死锁:
- 锁顺序:确保所有线程按照相同的顺序获取锁。
- 锁超时:使用带超时的锁尝试方法,防止无限期等待。
- 锁分离:尽量减少锁的粒度,避免一个锁保护过多的资源。
-
避免活锁:
- 退避策略:使用退避策略,使线程在无法获取锁时主动等待一段时间再尝试。
-
避免饥饿:
- 公平锁:使用公平锁确保所有线程都有机会获取锁。
- 优先级调度:合理设置线程优先级,避免低优先级线程长期无法获取锁。
-
避免竞态条件:
- 原子操作:使用原子操作类(如
AtomicInteger)来避免竞态条件。 - 锁保护:使用锁来保护共享资源的访问。
- 原子操作:使用原子操作类(如
-
避免过度同步:
- 最小化同步范围:只在必要的代码块中使用同步,避免同步整个方法。
- 细粒度锁:使用细粒度锁来提高并发性能。
-
使用高级同步工具:
- Condition:使用
Condition类来实现更灵活的等待和通知机制。 - Semaphore:使用
Semaphore控制同时访问某个资源的线程数量。 - CountDownLatch:使用
CountDownLatch让一个或多个线程等待其他线程完成某个操作。 - CyclicBarrier:使用
CyclicBarrier让一组线程等待彼此到达一个屏障点。
- Condition:使用
思维导图(文字描述)
线程同步需要注意的事项
├── 避免死锁
│ ├── 锁顺序
│ ├── 锁超时
│ └── 锁分离
├── 避免活锁
│ └── 退避策略
├── 避免饥饿
│ ├── 公平锁
│ └── 优先级调度
├── 避免竞态条件
│ ├── 原子操作
│ └── 锁保护
├── 避免过度同步
│ ├── 最小化同步范围
│ └── 细粒度锁
└── 使用高级同步工具
├── Condition
├── Semaphore
├── CountDownLatch
└── CyclicBarrier
Java代码示例
避免死锁
public class DeadlockAvoidance {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
System.out.println("Method 1: Acquired lock1");
synchronized (lock2) {
System.out.println("Method 1: Acquired lock2");
}
}
}
public void method2() {
synchronized (lock2) {
System.out.println("Method 2: Acquired lock2");
synchronized (lock1) {
System.out.println("Method 2: Acquired lock1");
}
}
}
public static void main(String[] args) {
DeadlockAvoidance example = new DeadlockAvoidance();
Thread t1 = new Thread(() -> example.method1());
Thread t2 = new Thread(() -> example.method2());
t1.start();
t2.start();
}
}
避免活锁
public class LivelockAvoidance {
private volatile boolean flag = false;
public void method1() {
while (flag) {
System.out.println("Method 1: Waiting...");
try {
Thread.sleep(100); // 退避策略
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Method 1: Executing...");
}
public void method2() {
while (!flag) {
System.out.println("Method 2: Waiting...");
try {
Thread.sleep(100); // 退避策略
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Method 2: Executing...");
}
public static void main(String[] args) {
LivelockAvoidance example = new LivelockAvoidance();
Thread t1 = new Thread(() -> example.method1());
Thread t2 = new Thread(() -> example.method2());
t1.start();
t2.start();
// 模拟外部条件变化
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
example.flag = true;
}
}
避免饥饿
import java.util.concurrent.locks.ReentrantLock;
public class FairnessLock {
private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
public void method() {
lock.lock();
try {
System.out.println("Method: Executing...");
// 模拟长时间操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
FairnessLock example = new FairnessLock();
Thread t1 = new Thread(() -> example.method());
Thread t2 = new Thread(() -> example.method());
t1.start();
t2.start();
}
}
避免竞态条件
import java.util.concurrent.atomic.AtomicInteger;
public class RaceConditionAvoidance {
private final AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException {
RaceConditionAvoidance example = new RaceConditionAvoidance();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
example.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
example.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final counter value: " + example.counter.get());
}
}
代码解释
-
避免死锁:
method1和method2分别尝试按不同顺序获取lock1和lock2,容易导致死锁。- 为了避免死锁,应确保所有线程按照相同的顺序获取锁。
-
避免活锁:
method1和method2在flag不满足条件时会不断尝试获取锁,使用Thread.sleep实现退避策略。- 通过外部条件变化(如
example.flag = true)来解除等待。
-
避免饥饿:
- 使用
ReentrantLock的公平模式,确保所有线程都有机会获取锁。 - 模拟长时间操作,验证公平锁的效果。
- 使用
-
避免竞态条件:
- 使用
AtomicInteger来原子性地递增计数器,避免竞态条件。 - 创建两个线程分别对计数器进行10000次递增操作,最终输出计数器的值。
- 使用
通过这些注意事项和示例代码,可以有效地实现线程同步,避免常见的多线程问题。
79

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



