1. 数据不一致
问题描述
数据不一致是指多个线程并发访问和修改共享数据时,由于缺乏有效的同步机制,导致数据的最终状态不符合预期。这通常发生在读写操作交织的情况下。
解决方案
-
Synchronized 关键字
- 方法级别同步:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }
- 代码块级别同步:
public class Counter { private int count = 0; private final Object lock = new Object(); public void increment() { synchronized (lock) { count++; } } public int getCount() { synchronized (lock) { return count; } } }
- 方法级别同步:
-
Lock 接口
- 使用
ReentrantLock
:import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public 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() { lock.lock(); try { return count; } finally { lock.unlock(); } } }
- 使用
-
原子类
- 使用
AtomicInteger
:import java.util.concurrent.atomic.AtomicInteger; public class Counter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }
- 使用
2. 可见性问题
问题描述
可见性问题是指一个线程对共享变量的修改不能及时被其他线程看到。这是因为每个线程可能有自己的缓存,导致内存模型不一致。
解决方案
-
Volatile 关键字
- 确保变量的最新值对所有线程可见,并禁止编译器和处理器重排序:
public class VisibilityExample { private volatile boolean flag = false; public void writer() { flag = true; } public void reader() { while (!flag) { // Do something } } }
- 确保变量的最新值对所有线程可见,并禁止编译器和处理器重排序:
-
Synchronized 关键字
- 同步代码块或方法也可以保证可见性:
public class VisibilityExample { private boolean flag = false; public synchronized void writer() { flag = true; } public synchronized void reader() { while (!flag) { // Do something } } }
- 同步代码块或方法也可以保证可见性:
3. 原子性问题
问题描述
原子性问题是指某些看似简单的操作实际上可能涉及多个步骤,如果这些步骤被其他线程打断,可能会导致错误的结果。
解决方案
-
Synchronized 关键字
- 确保操作的原子性:
public class BankAccount { private int balance = 0; public synchronized void deposit(int amount) { if (amount > 0) { balance += amount; } } public synchronized void withdraw(int amount) { if (amount > 0 && amount <= balance) { balance -= amount; } } public synchronized int getBalance() { return balance; } }
- 确保操作的原子性:
-
原子类
- 使用
AtomicInteger
等原子类:import java.util.concurrent.atomic.AtomicInteger; public class BankAccount { private AtomicInteger balance = new AtomicInteger(0); public void deposit(int amount) { if (amount > 0) { balance.addAndGet(amount); } } public void withdraw(int amount) { if (amount > 0 && balance.compareAndSet(amount, balance.get() - amount)) { // Withdrawal successful } } public int getBalance() { return balance.get(); } }
- 使用
4. 死锁
问题描述
死锁是指两个或多个线程相互等待对方持有的锁,而无法继续执行的情况。
预防措施
-
锁顺序
- 确保所有线程按照相同的顺序获取锁:
public class DeadlockExample { private final Object lock1 = new Object(); private final Object lock2 = new Object(); public void method1() { synchronized (lock1) { synchronized (lock2) { // Do something } } } public void method2() { synchronized (lock1) { synchronized (lock2) { // Do something } } } }
- 确保所有线程按照相同的顺序获取锁:
-
锁超时
- 使用
tryLock(long time, TimeUnit unit)
方法尝试获取锁:import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class DeadlockExample { private final ReentrantLock lock1 = new ReentrantLock(); private final ReentrantLock lock2 = new ReentrantLock(); public void method1() { boolean locked1 = false; boolean locked2 = false; try { locked1 = lock1.tryLock(1, TimeUnit.SECONDS); locked2 = lock2.tryLock(1, TimeUnit.SECONDS); if (locked1 && locked2) { // Do something } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (locked1) { lock1.unlock(); } if (locked2) { lock2.unlock(); } } } public void method2() { boolean locked1 = false; boolean locked2 = false; try { locked1 = lock2.tryLock(1, TimeUnit.SECONDS); locked2 = lock1.tryLock(1, TimeUnit.SECONDS); if (locked1 && locked2) { // Do something } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (locked1) { lock2.unlock(); } if (locked2) { lock1.unlock(); } } } }
- 使用
5. 饿死(Starvation)
问题描述
饿死是指某些线程因为长时间无法获得必要的资源而无法运行。
解决方案
-
公平锁
- 使用
ReentrantLock
的公平锁模式:import java.util.concurrent.locks.ReentrantLock; public class FairLockExample { private final ReentrantLock lock = new ReentrantLock(true); public void method() { lock.lock(); try { // Do something } finally { lock.unlock(); } } }
- 使用
-
线程优先级
- 合理设置线程优先级,避免高优先级线程长期占用资源:
Thread thread1 = new Thread(() -> { // Do something }); thread1.setPriority(Thread.MIN_PRIORITY); thread1.start();
- 合理设置线程优先级,避免高优先级线程长期占用资源: