并发编程挑战:Java线程同步和死锁问题实例

原创 川长思鸟来 2024-10-23 13:09 125阅读 0赞

在Java中,线程同步和死锁是两个主要的并发问题。下面分别给出这两个问题的例子:

  1. 线程同步问题(使用synchronized关键字)
  1. // 假设我们有一个银行账户类
  2. public class BankAccount {
  3. private int balance;
  4. // 同步方法,确保在同一时刻只有一个线程执行这个方法
  5. public synchronized void deposit(int amount) {
  6. balance += amount;
  7. System.out.println("Deposit: Amount=" + amount + ", Balance=" + balance);
  8. }
  9. // 同步方法,确保在同一时刻只有一个线程执行这个方法
  10. public synchronized void withdraw(int amount) {
  11. if (amount > balance) {
  12. System.out.println("Withdrawal: Amount=" + amount + ", Insufficient balance");
  13. return;
  14. }
  15. balance -= amount;
  16. System.out.println("Withdrawal: Amount=" + amount + ", Balance=" + balance);
  17. }
  18. }
  19. // 示例:两个线程同时存款和取款
  20. public class ThreadExample {
  21. public static void main(String[] args) {
  22. BankAccount account = new BankAccount();
  23. // 创建两个线程,一个存钱,一个取钱
  24. Thread depositThread = new Thread(() -> {
  25. for (int i = 1; i <= 500; i++) {
  26. account.deposit(i);
  27. try {
  28. Thread.sleep(200); // 模拟操作时间
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }));
  34. Thread withdrawThread = new Thread(() -> {
  35. for (int i = 1; i <= 500; i++) {
  36. account.withdraw(i);
  37. try {
  38. Thread.sleep(200); // 模拟操作时间
  39. } catch (InterruptedException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. }));
  44. depositThread.start(); // 开始存款线程
  45. withdrawThread.start(); // 开始取款线程
  46. System.out.println("Program execution complete.");
  47. }
  48. }

这段代码会创建两个线程,一个存款(depositThread),另一个取款(withdrawThread)。由于存款和取款方法都是同步的,因此在运行过程中不会出现同时进行存款和取款的情况,也就避免了死锁问题。

  1. 死锁问题(两个线程相互等待对方释放资源)
  1. // 假设我们有一个银行账户类,并且存在以下情况
  2. public class BankAccount {
  3. private int balance;
  4. // 两个同步方法,相互等待对方释放资源
  5. public synchronized void deposit(int amount) throws InterruptedException {
  6. if (amount > balance) {
  7. System.out.println("Deposit: Amount=" + amount + ", Insufficient balance");
  8. throw new InterruptedException(); // 在存款失败时抛出异常并中断线程
  9. }
  10. balance += amount;
  11. System.out.println("Deposit: Amount=" + amount + ", Balance=" + balance);
  12. }
  13. public synchronized void withdraw(int amount) throws InterruptedException {
  14. if (amount > balance) {
  15. System.out.println("Withdrawal: Amount=" + amount + ", Insufficient balance");
  16. throw new InterruptedException(); // 在取款失败时抛出异常并中断线程
  17. }
  18. balance -= amount;
  19. System.out.println("Withdrawal: Amount=" + amount + ", Balance=" + balance);
  20. }
  21. }

在这个例子中,deposit(int amount)withdraw(int amount) 两个方法都是同步的,它们会相互等待对方释放资源。这就可能导致死锁问题:两个线程互相等待对方释放资源,结果都陷入无限循环,无法继续执行。

要避免这种问题,可以采用以下策略:

  • 设置超时时间:在尝试获取资源(如存款、取款)超过一定时间后,抛出异常并中断线程。这样可以减少死锁的可能。
  • 使用无等待模式:某些并发框架或库提供了无等待模式,即当一个线程调用一个需要同步的资源方法时,不会阻塞当前线程,而是立即返回(通常是一个内部表示状态的对象)。

请根据实际情况选择合适的避免死锁的方法。

文章版权声明:注明蒲公英云原创文章,转载或复制请以超链接形式并注明出处。

发表评论

表情:
评论列表 (有 0 条评论,125人围观)

还没有评论,来说两句吧...

相关阅读