深入解析Java线程安全:从数据不一致到死锁的全面应对策略

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();
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值