理解和避免:Java多线程同步问题示例

原创 小咪咪 2024-12-13 23:48 100阅读 0赞

在Java多线程编程中,同步问题是非常常见的。当多个线程同时访问和修改共享资源时,如果没有适当的控制,就可能导致数据不一致或者程序崩溃。

以下是一些典型的Java多线程同步问题的示例:

  1. 竞态条件(Race Condition):两个或多个线程同时执行一个操作,导致预期结果未出现。
    ```java
    class Counter {
    private int count = 0;

    public synchronized void increment() {

    1. count++;

    }

    public synchronized int decrement() {

    1. if (count > 0) {
    2. count--;
    3. }
    4. return count;

    }

    public synchronized int getCount() {

    1. return count;

    }
    }

public class Main {
public static void main(String[] args) {
Counter counter = new Counter();

  1. Thread thread1 = new Thread(() -> {
  2. for (int i = 0; i < 5; i++) {
  3. counter.increment();
  4. }
  5. }));
  6. Thread thread2 = new Thread(() -> {
  7. for (int i = 4; i >= 0; i--) {
  8. counter.decrement();
  9. }
  10. }));
  11. thread1.start();
  12. thread2.start();
  13. // 这里可能会导致程序错误,因为无法保证线程执行的顺序和同步条件
  14. // counter.getCount();
  15. try {
  16. thread1.join();
  17. thread2.join();
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. System.out.println("Counter count: " + counter.getCount()); // 输出:Counter count: 0
  22. }

}

  1. 2. **死锁(Deadlock)**:两个或多个线程相互等待对方释放资源,导致都无法继续执行。
  2. ```java
  3. class LockResource {
  4. private Object resource = new Object();
  5. public synchronized void acquire() {
  6. while (resource != null) { // 假设一个资源只能被一个线程持有
  7. try:
  8. wait();
  9. catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. resource = new Object(); // 赋予资源
  14. }
  15. public synchronized void release() {
  16. if (resource != null) { // 检查资源是否被占用
  17. resource = null; // 取消资源
  18. notifyAll(); // 通知所有等待的线程资源已释放
  19. }
  20. }
  21. }
  22. public class Main {
  23. public static void main(String[] args) {
  24. LockResource lockResource = new LockResource();
  25. Thread thread1 = new Thread(() -> {
  26. try {
  27. lockResource.acquire();
  28. System.out.println("Thread 1 acquired resource.");
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. }));
  33. Thread thread2 = new Thread(() -> {
  34. try {
  35. lockResource.acquire(); // 此处会阻塞,直到thread1释放资源
  36. System.out.println("Thread 2 acquired resource.");
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. }));
  41. thread1.start();
  42. thread2.start();
  43. try {
  44. thread1.join();
  45. thread2.join();
  46. } catch (InterruptedException e) {
  47. e.printStackTrace();
  48. }
  49. lockResource.release(); // 在main方法结束前释放资源
  50. }
  51. }
  1. 饥饿问题(Starvation):一个线程可能因为等待某个条件满足而长时间得不到执行机会,导致资源被其他线程长时间占用。
    ```java
    class SynchronizedCounter {
    private int count = 0;

    public synchronized void increment() {

    1. count++;

    }

    public synchronized int decrement() {

    1. if (count > 0) {
    2. count--;
    3. }
    4. return count;

    }

    public synchronized boolean isEmpty() {

    1. return count == 0;

    }
    }

public class Main {
public static void main(String[] args) {
SynchronizedCounter counter = new SynchronizedCounter();

  1. Thread thread1 = new Thread(() -> {
  2. for (int i = 5; i > 0; i--) { // 这个循环会无限次执行
  3. counter.increment();
  4. try {
  5. Thread.sleep(100);
  6. } catch (InterruptedException e) {
  7. e.printStackTrace();
  8. }
  9. }
  10. }));
  11. thread1.start();
  12. while (!counter.isEmpty())) { // 当计数器不为空时循环
  13. System.out.println("Counter count: " + counter.decrement());
  14. try {
  15. Thread.sleep(500);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. thread1.join(); // 等待线程结束
  21. System.out.println("Counter count after thread join: " + counter.getCount())); // 此时计数器应该已经被释放
  22. }

}
`` 以上示例中,线程1无限次执行循环,导致同步问题。为了避免这些问题,通常需要使用适当的并发控制机制,如synchronized关键字、ReentrantLock`等。

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

发表评论

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

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

相关阅读