• 系列五、线程间通信


    一、synchronized实现

    1.1、案例一(2个线程交替对变量执行+1、-1操作,来10轮)

    1.1.1、资源类ShareDataOne

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 10:44
    4. * @Description: 资源类
    5. * 说明:2个线程使用if判断变量的值,没有问题,3个及3个以上线程会出现虚假唤醒的问题,需要注意!!!!!
    6. */
    7. public class ShareDataOne {
    8. private int number = 0;
    9. /**
    10. * 加1
    11. *
    12. * @throws InterruptedException
    13. */
    14. public synchronized void increment() throws InterruptedException {
    15. // 1、判断
    16. if (number != 0) {
    17. this.wait();
    18. }
    19. // 2、干活
    20. ++number;
    21. System.out.println(Thread.currentThread().getName() + "\t" + number);
    22. // 3、通知
    23. this.notifyAll();
    24. }
    25. /**
    26. * 减1
    27. *
    28. * @throws InterruptedException
    29. */
    30. public synchronized void decrement() throws InterruptedException {
    31. // 1、判断
    32. if (number == 0) {
    33. this.wait();
    34. }
    35. // 2、干活
    36. --number;
    37. System.out.println(Thread.currentThread().getName() + "\t" + number);
    38. // 3、通知
    39. this.notifyAll();
    40. }
    41. }

    1.1.2、线程类ShareDataOneMainApp

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 10:46
    4. * @Description:
    5. * 需求:两个线程,可以操作初始量为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替来10轮
    6. * Java里边如何进行工程级别的多线程编写?
    7. * 1、多线程编程模板(套路上)
    8. * 1.1、线程 操作 资源类
    9. * 1.2、高内聚 低耦合
    10. *
    11. * 2、多线程编程模板(套路下)
    12. * 2.1、判断
    13. * 2.2、干活
    14. * 2.3、通知
    15. *
    16. * 3、防止虚假唤醒用while
    17. */
    18. public class ShareDataOneMainApp {
    19. public static void main(String[] args) {
    20. ShareDataOne sd = new ShareDataOne();
    21. new Thread(() -> {
    22. for (int i = 1; i <= 10; i++) {
    23. try {
    24. sd.increment();
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. }, "A").start();
    30. new Thread(() -> {
    31. for (int i = 1; i <= 10; i++) {
    32. try {
    33. sd.decrement();
    34. } catch (Exception e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }, "B").start();
    39. }
    40. }

    1.1.3、结果

    1.2、案例二(4个线程交替对变量执行+1、-1操作,来10轮) 

    1.2.1、资源类ShareDataTwo

    /**
     * @Author : 一叶浮萍归大海
     * @Date: 2023/11/20 10:44
     * @Description: 资源类
     * 说明:2个线程使用if判断变量的值,没有问题,3个及3个以上线程会出现虚假唤醒的问题,需要注意!!!!!
     * 解决方法:使用while做判断条件
     * 原理:中断和虚假唤醒是由可能产生的,所以要用loob循环,if只判断一次,while是只要唤醒就要拉回来再判断一次,if换成while即可解决虚假唤醒的问题
     */
    public class ShareDataTwo {
        private int number = 0;
    
        /**
         * 加1
         *
         * @throws InterruptedException
         */
        public synchronized void increment() throws InterruptedException {
            // 1、判断
            while (number != 0) {
                this.wait();
            }
    
            // 2、干活
            ++number;
            System.out.println(Thread.currentThread().getName() + "\t" + number);
    
            // 3、通知
            this.notifyAll();
        }
    
        /**
         * 减1
         *
         * @throws InterruptedException
         */
        public synchronized void decrement() throws InterruptedException {
            // 1、判断
            while (number == 0) {
                this.wait();
            }
    
            // 2、干活
            --number;
            System.out.println(Thread.currentThread().getName() + "\t" + number);
    
            // 3、通知
            this.notifyAll();
        }
    }

    1.2.2、线程类

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 11:19
    4. * @Description:
    5. * 需求:四个线程,可以操作初始量为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替来10轮
    6. * Java里边如何进行工程级别的多线程编写?
    7. * 1、多线程编程模板(套路上)
    8. * 1.1、线程 操作 资源类
    9. * 1.2、高内聚 低耦合
    10. *
    11. * 2、多线程编程模板(套路下)
    12. * 2.1、判断
    13. * 2.2、干活
    14. * 2.3、通知
    15. *
    16. * 3、防止虚假唤醒用while
    17. */
    18. public class ShareDataTwoMainApp {
    19. public static void main(String[] args) {
    20. ShareDataTwo sdt = new ShareDataTwo();
    21. new Thread(() -> {
    22. for (int i = 1; i <= 10; i++) {
    23. try {
    24. sdt.increment();
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. }, "A").start();
    30. new Thread(() -> {
    31. for (int i = 1; i <= 10; i++) {
    32. try {
    33. sdt.decrement();
    34. } catch (Exception e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }, "B").start();
    39. new Thread(() -> {
    40. for (int i = 1; i <= 10; i++) {
    41. try {
    42. sdt.increment();
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. }, "C").start();
    48. new Thread(() -> {
    49. for (int i = 1; i <= 10; i++) {
    50. try {
    51. sdt.decrement();
    52. } catch (Exception e) {
    53. e.printStackTrace();
    54. }
    55. }
    56. }, "D").start();
    57. }
    58. }

    1.2.3、结果

    二、Condition实现

    2.1、案例一(2个线程交替对变量执行+1、-1操作,来10轮)

    2.1.1、资源类ShareDataThree

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 11:40
    4. * @Description: 资源类
    5. * 说明:2个线程使用if判断变量的值,没有问题,3个及3个以上线程会出现虚假唤醒的问题,需要注意!!!!!
    6. * 解决方法:使用while做判断条件
    7. * 原理:中断和虚假唤醒是由可能产生的,所以要用loob循环,if只判断一次,while是只要唤醒就要拉回来再判断一次,if换成while即可解决虚假唤醒的问题
    8. */
    9. public class ShareDataThree {
    10. private Integer number = 0;
    11. private Lock lock = new ReentrantLock();
    12. private Condition condition = lock.newCondition();
    13. /**
    14. * 加1
    15. */
    16. public void increment() {
    17. lock.lock();
    18. try {
    19. // 判断
    20. while (number != 0) {
    21. condition.await();
    22. }
    23. // 干活
    24. ++number;
    25. System.out.println(Thread.currentThread().getName() + "\t" + number);
    26. // 通知
    27. condition.signalAll();
    28. } catch (Exception e) {
    29. e.printStackTrace();
    30. } finally {
    31. lock.unlock();
    32. }
    33. }
    34. /**
    35. * 加1
    36. */
    37. public void decrement() {
    38. lock.lock();
    39. try {
    40. // 判断
    41. while (number == 0) {
    42. condition.await();
    43. }
    44. // 干活
    45. --number;
    46. System.out.println(Thread.currentThread().getName() + "\t" + number);
    47. // 通知
    48. condition.signalAll();
    49. } catch (Exception e) {
    50. e.printStackTrace();
    51. } finally {
    52. lock.unlock();
    53. }
    54. }
    55. }

    2.1.2、线程类ShareDataThreeMainApp

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 11:19
    4. * @Description:
    5. * 需求:两个线程,可以操作初始量为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替来10轮
    6. * Java里边如何进行工程级别的多线程编写?
    7. * 1、多线程编程模板(套路上)
    8. * 1.1、线程 操作 资源类
    9. * 1.2、高内聚 低耦合
    10. *
    11. * 2、多线程编程模板(套路下)
    12. * 2.1、判断
    13. * 2.2、干活
    14. * 2.3、通知
    15. *
    16. * 3、防止虚假唤醒用while
    17. */
    18. public class ShareDataThreeMainApp {
    19. public static void main(String[] args) {
    20. ShareDataThree sdt = new ShareDataThree();
    21. new Thread(() -> {
    22. for (int i = 1; i <= 10; i++) {
    23. try {
    24. sdt.increment();
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. }, "A").start();
    30. new Thread(() -> {
    31. for (int i = 1; i <= 10; i++) {
    32. try {
    33. sdt.decrement();
    34. } catch (Exception e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }, "B").start();
    39. }
    40. }

     2.1.3、结果

    2.2、案例二(4个线程交替对变量执行+1、-1操作,来10轮) 

    2.2.1、资源类ShareDataThree

    同2.1.1。

    2.2.2、线程类

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 11:19
    4. * @Description:
    5. * 需求:四个线程,可以操作初始量为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替来10轮
    6. * Java里边如何进行工程级别的多线程编写?
    7. * 1、多线程编程模板(套路上)
    8. * 1.1、线程 操作 资源类
    9. * 1.2、高内聚 低耦合
    10. *
    11. * 2、多线程编程模板(套路下)
    12. * 2.1、判断
    13. * 2.2、干活
    14. * 2.3、通知
    15. *
    16. * 3、防止虚假唤醒用while
    17. */
    18. public class ShareDataFourMainApp {
    19. public static void main(String[] args) {
    20. ShareDataThree sdt = new ShareDataThree();
    21. new Thread(() -> {
    22. for (int i = 1; i <= 10; i++) {
    23. try {
    24. sdt.increment();
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. }, "A").start();
    30. new Thread(() -> {
    31. for (int i = 1; i <= 10; i++) {
    32. try {
    33. sdt.decrement();
    34. } catch (Exception e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }, "B").start();
    39. new Thread(() -> {
    40. for (int i = 1; i <= 10; i++) {
    41. try {
    42. sdt.increment();
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. }, "C").start();
    48. new Thread(() -> {
    49. for (int i = 1; i <= 10; i++) {
    50. try {
    51. sdt.decrement();
    52. } catch (Exception e) {
    53. e.printStackTrace();
    54. }
    55. }
    56. }, "D").start();
    57. }
    58. }

    2.2.3、结果

    三、线程间定制化通信

    3.1、资源类ShareDataFive

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 12:12
    4. * @Description: 资源类
    5. * 说明:2个线程使用if判断变量的值,没有问题,3个及3个以上线程会出现虚假唤醒的问题,需要注意!!!!!
    6. * 解决方法:使用while做判断条件
    7. * 原理:中断和虚假唤醒是由可能产生的,所以要用loob循环,if只判断一次,while是只要唤醒就要拉回来再判断一次,if换成while即可解决虚假唤醒的问题
    8. */
    9. public class ShareDataFive {
    10. private Integer number = 1;
    11. private Lock lock = new ReentrantLock();
    12. private Condition condition1 = lock.newCondition();
    13. private Condition condition2 = lock.newCondition();
    14. private Condition condition3 = lock.newCondition();
    15. public void print5(int totalLoopNumber) {
    16. lock.lock();
    17. try {
    18. // 判断
    19. while (number != 1) {
    20. condition1.await();
    21. }
    22. // 干活
    23. for (int i = 1; i <= totalLoopNumber; i++) {
    24. System.out.println("【当前线程】:" + Thread.currentThread().getName() + ",【当前i的值】:" + i + ",【totalLoopNumber】:" + totalLoopNumber);
    25. }
    26. // 通知
    27. number = 2;
    28. condition2.signal();
    29. } catch (Exception e) {
    30. e.printStackTrace();
    31. } finally {
    32. lock.unlock();
    33. }
    34. }
    35. public void print10(int totalLoopNumber) {
    36. lock.lock();
    37. try {
    38. // 判断
    39. while (number != 2) {
    40. condition2.await();
    41. }
    42. // 干活
    43. for (int i = 1; i <= totalLoopNumber; i++) {
    44. System.out.println("【当前线程】:" + Thread.currentThread().getName() + ",【当前i的值】:" + i + ",【totalLoopNumber】:" + totalLoopNumber);
    45. }
    46. // 通知
    47. number = 3;
    48. condition3.signal();
    49. } catch (Exception e) {
    50. e.printStackTrace();
    51. } finally {
    52. lock.unlock();
    53. }
    54. }
    55. public void print15(int totalLoopNumber) {
    56. lock.lock();
    57. try {
    58. // 判断
    59. while (number != 3) {
    60. condition3.await();
    61. }
    62. // 干活
    63. for (int i = 1; i <= totalLoopNumber; i++) {
    64. System.out.println("【当前线程】:" + Thread.currentThread().getName() + ",【当前i的值】:" + i + ",【totalLoopNumber】:" + totalLoopNumber);
    65. }
    66. // 通知
    67. number = 1;
    68. condition1.signal();
    69. } catch (Exception e) {
    70. e.printStackTrace();
    71. } finally {
    72. lock.unlock();
    73. }
    74. }
    75. }

    3.2、线程类

    1. /**
    2. * @Author : 一叶浮萍归大海
    3. * @Date: 2023/11/20 12:22
    4. * @Description: 需求:多个线程之间按顺序调用,实现AA>BB>CC,三个线程启动,
    5. * 要求:
    6. * AA打印5次,BB打印10次,CC打印15次
    7. * 接着,AA打印5次,BB打印10次,CC打印15次
    8. * ...
    9. * 来10轮
    10. */
    11. public class ShareDataFiveMainApp {
    12. public static void main(String[] args) {
    13. ShareDataFive sdf = new ShareDataFive();
    14. new Thread(() -> {
    15. for (int i = 1; i <= 10; i++) {
    16. sdf.print5(5);
    17. }
    18. }, "AA").start();
    19. new Thread(() -> {
    20. for (int i = 1; i <= 10; i++) {
    21. sdf.print10(10);
    22. }
    23. }, "BB").start();
    24. new Thread(() -> {
    25. for (int i = 1; i <= 10; i++) {
    26. sdf.print15(15);
    27. }
    28. }, "CC").start();
    29. }
    30. }

    3.3、结果

     

  • 相关阅读:
    重写与重载笔记
    Android学习笔记 63. 添加一个ScrollView
    实验五 函数文件(matlab)
    LeetCode 热题 HOT 100 第八十天 494. 目标和 中等题 用python3求解
    redis--高可用之持久化
    【Python】设计模式
    opencv 双目立体视觉
    生产脚本1
    python创建exe文件
    奥特曼与钢铁侠【InsCode Stable Diffusion美图活动一期】
  • 原文地址:https://blog.csdn.net/HelloWorld20161112/article/details/134502939