• java 多线程&wait条件发生变化与使用while的必要性——77


            在使用wait/notify模式时,还需要注意一种情况,即wait 条件发生变化,容易造成逻辑的混乱。

    创建类Add.java

    1. package chapter3.test3_1.test3_1_18;
    2. public class Add {
    3. private String lock;
    4. public Add(String lock) {
    5. super();
    6. this.lock = lock;
    7. }
    8. public void add() {
    9. synchronized (lock) {
    10. ValueObject.list.add("anyString");
    11. lock.notifyAll();
    12. }
    13. }
    14. }

     创建类Subtract.java

    1. package chapter3.test3_1.test3_1_18;
    2. public class Subtract {
    3. private String lock;
    4. public Subtract(String lock) {
    5. super();
    6. this.lock = lock;
    7. }
    8. public void subtract() {
    9. try {
    10. synchronized (lock) {
    11. if (ValueObject.list.size() == 0) {
    12. System.out.println("wait begin ThreadName=" + Thread.currentThread().getName());
    13. lock.wait();
    14. System.out.println("wait end ThreadName=" + Thread.currentThread().getName());
    15. }
    16. ValueObject.list.remove(0);
    17. System.out.println("list size=" + ValueObject.list.size());
    18. }
    19. } catch (InterruptedException e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. }

    ValueObject.java代码

    1. package chapter3.test3_1.test3_1_18;
    2. import java.util.ArrayList;
    3. import java.util.List;
    4. public class ValueObject {
    5. public static List list = new ArrayList();
    6. }

    两个线程类代码

    1. package chapter3.test3_1.test3_1_18;
    2. public class ThreadAdd extends Thread {
    3. private Add p;
    4. public ThreadAdd(Add p) {
    5. super();
    6. this.p = p;
    7. }
    8. @Override
    9. public void run() {
    10. p.add();
    11. }
    12. }
    1. package chapter3.test3_1.test3_1_18;
    2. public class ThreadSubtract extends Thread {
    3. private Subtract r;
    4. public ThreadSubtract(Subtract r) {
    5. super();
    6. this.r = r;
    7. }
    8. @Override
    9. public void run() {
    10. r.subtract();
    11. }
    12. }

    Run.java代码

    1. package chapter3.test3_1.test3_1_18;
    2. public class Run {
    3. public static void main(String[] args) throws InterruptedException {
    4. String lock = new String("");
    5. Add add = new Add(lock);
    6. Subtract subtract = new Subtract(lock);
    7. ThreadSubtract subtract1Thread = new ThreadSubtract(subtract);
    8. subtract1Thread.setName("subtract1Thread");
    9. subtract1Thread.start();
    10. ThreadSubtract subtract2Thread = new ThreadSubtract(subtract);
    11. subtract2Thread.setName("subtract2Thread");
    12. subtract2Thread.start();
    13. Thread.sleep(1000);
    14. ThreadAdd addThread = new ThreadAdd(add);
    15. addThread.setName("addThread");
    16. addThread.start();
    17. }
    18. }

    程序运行结果

    出现异常的原因 

            出现异常的原因是有两个实现删除remove()操作的线程,它们在 “Thread.sleep 1000 ); 之前都执行了wait()方法,呈等待状态,当加操作的线程在1s之后被运行时,通知了所有呈等待状态的减操作线程,那么第一个实现减操作的线程能正确地删除 list 中索引为 0的数据,但第二个实现减操作的线程则出现索引溢出的异常,因为list中仅仅添加了一个数据,也只能删除一个数据,没有第二个数据可供删除,所以出现了java.lang.Index-OutOfBoundsException 异常。

    如何解决这种情况呢?更改Subtract.java中的subtract方法代码

     

    1. package chapter3.test3_1.test3_1_18.test1;
    2. public class Subtract {
    3. private String lock;
    4. public Subtract(String lock) {
    5. super();
    6. this.lock = lock;
    7. }
    8. public void subtract() {
    9. try {
    10. synchronized (lock) {
    11. while (ValueObject.list.size() == 0) {
    12. System.out.println("wait begin ThreadName=" + Thread.currentThread().getName());
    13. lock.wait();
    14. System.out.println("wait end ThreadName=" + Thread.currentThread().getName());
    15. }
    16. ValueObject.list.remove(0);
    17. System.out.println("list size=" + ValueObject.list.size());
    18. }
    19. } catch (InterruptedException e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. }

    程序运行结果

    不再出现异常 

  • 相关阅读:
    Java内存区域与内存溢出异常
    智慧社区搭载联网智能门锁,出行体验不一般!
    全新力作—C++ string类的模拟实现
    面试-Redis常见场景
    程序环境和预处理(Program environment and processing)
    EXPLAIN的使用
    用prim和kruskal算法求最小生成树问题
    软件测试技术之iOS 单元测试—逻辑测试
    数据报表的种类
    【Confluence】使用start-confluence.sh命令重启后提示找不到网页HTTP404
  • 原文地址:https://blog.csdn.net/zp357252539/article/details/125477106