线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析
场景—-两个线程,一个线程对当前数值加 1,另一个线程对当前数值减 1,要求用线程间通信

1. synchronized方案

  1. package com.atguigu.test;
  2. /**
  3. * volatile 关键字实现线程交替加减
  4. */
  5. public class TestVolatile {
  6. /**
  7. * 交替加减
  8. * @param args
  9. */
  10. public static void main(String[] args){
  11. DemoClass demoClass = new DemoClass();
  12. new Thread(() ->{
  13. for (int i = 0; i < 5; i++) {
  14. demoClass.increment();
  15. }
  16. }, "线程 A").start();
  17. new Thread(() ->{
  18. for (int i = 0; i < 5; i++) {
  19. demoClass.decrement();
  20. }
  21. }, "线程 B").start();
  22. }
  23. }
  24. package com.atguigu.test;
  25. class DemoClass{
  26. //加减对象
  27. private int number = 0;
  28. /**
  29. * 加 1
  30. */
  31. public synchronized void increment() {
  32. try {
  33. while (number != 0){
  34. this.wait();
  35. }
  36. number++;
  37. System.out.println("--------" + Thread.currentThread().getName() + "加一成功----------,值为:" + number);
  38. notifyAll();
  39. }catch (Exception e){
  40. e.printStackTrace();
  41. }
  42. }
  43. /**
  44. * 减一
  45. */
  46. public synchronized void decrement(){
  47. try {
  48. while (number == 0){
  49. this.wait();
  50. }
  51. number--;
  52. System.out.println("--------" + Thread.currentThread().getName() + "减一成功----------,值为:" + number);
  53. notifyAll();
  54. }catch (Exception e){
  55. e.printStackTrace();
  56. }
  57. }
  58. }

2. Lock方案

  1. package com.atguigu.test;
  2. import java.util.concurrent.locks.Condition;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. class DemoClass{
  6. //加减对象
  7. private int number = 0;
  8. //声明锁
  9. private Lock lock = new ReentrantLock();
  10. //声明钥匙
  11. private Condition condition = lock.newCondition();
  12. /**
  13. * 加 1
  14. */
  15. public void increment() {
  16. try {
  17. lock.lock();
  18. while (number != 0){
  19. condition.await();
  20. }
  21. number++;
  22. System.out.println("--------" + Thread.currentThread().getName() + "加一成功----------,值为:" + number);
  23. condition.signalAll();
  24. }catch (Exception e){
  25. e.printStackTrace();
  26. }finally {
  27. lock.unlock();
  28. }
  29. }
  30. /**
  31. * 减一
  32. */
  33. public void decrement(){
  34. try {
  35. lock.lock();
  36. while (number == 0){
  37. condition.await();
  38. }
  39. number--;
  40. System.out.println("--------" + Thread.currentThread().getName() + "减一成功----------,值为:" + number);
  41. condition.signalAll();
  42. }catch (Exception e){
  43. e.printStackTrace();
  44. }finally {
  45. lock.unlock();
  46. }
  47. }
  48. }

4. 线程间定制化通信

4.1 案例介绍

==问题: A 线程打印 5 次 A, B 线程打印 10 次 B, C 线程打印 15 次 C,按照此顺序循环 10 轮==

4.2 实现流程

  1. package com.atguigu.test;
  2. import java.util.concurrent.locks.Condition;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. class DemoClass{
  6. //通信对象:0--打印 A 1---打印 B 2----打印 C
  7. private int number = 0;
  8. //声明锁
  9. private Lock lock = new ReentrantLock();
  10. //声明钥匙 A
  11. private Condition conditionA = lock.newCondition();
  12. //声明钥匙 B
  13. private Condition conditionB = lock.newCondition();
  14. //声明钥匙 C
  15. private Condition conditionC = lock.newCondition();/**
  16. * A 打印 5 次
  17. */
  18. public void printA(int j){
  19. try {
  20. lock.lock();
  21. while (number != 0){
  22. conditionA.await();
  23. }
  24. System.out.println(Thread.currentThread().getName() + "输出 A,第" + j + "轮开始");
  25. //输出 5 次 A
  26. for (int i = 0; i < 5; i++) {
  27. System.out.println("A");
  28. }
  29. //开始打印 B
  30. number = 1;
  31. //唤醒 B
  32. conditionB.signal();
  33. }catch (Exception e){
  34. e.printStackTrace();
  35. }finally {
  36. lock.unlock();
  37. }
  38. }
  39. /**
  40. * B 打印 10 次
  41. */
  42. public void printB(int j){
  43. try {
  44. lock.lock();
  45. while (number != 1){
  46. conditionB.await();
  47. }
  48. System.out.println(Thread.currentThread().getName() + "输出 B,第" + j + "轮开始");
  49. //输出 10 次 B
  50. for (int i = 0; i < 10; i++) {
  51. System.out.println("B");
  52. }
  53. //开始打印 C
  54. number = 2;
  55. //唤醒 C
  56. conditionC.signal();
  57. }catch (Exception e){
  58. e.printStackTrace();
  59. }finally {
  60. lock.unlock();
  61. }
  62. }
  63. /**
  64. * C 打印 15 次
  65. */
  66. public void printC(int j){
  67. try {
  68. lock.lock();
  69. while (number != 2){
  70. conditionC.await();
  71. }
  72. System.out.println(Thread.currentThread().getName() + "输出 C,第" + j + "轮开始");
  73. //输出 15 次 C
  74. for (int i = 0; i < 15; i++) {
  75. System.out.println("C");
  76. }
  77. System.out.println("-----------------------------------------");
  78. //开始打印 A
  79. number = 0;
  80. //唤醒 A
  81. conditionA.signal();
  82. }catch (Exception e){
  83. e.printStackTrace();
  84. }finally {
  85. lock.unlock();
  86. }
  87. }
  88. }

测试类

  1. package com.atguigu.test;
  2. /**
  3. * volatile 关键字实现线程交替加减
  4. */
  5. public class TestVolatile {
  6. /**
  7. * 交替加减
  8. * @param args
  9. */
  10. public static void main(String[] args){
  11. DemoClass demoClass = new DemoClass();
  12. new Thread(() ->{
  13. for (int i = 1; i <= 10; i++) {
  14. demoClass.printA(i);
  15. }
  16. }, "A 线程").start();
  17. new Thread(() ->{
  18. for (int i = 1; i <= 10; i++) {
  19. demoClass.printB(i);
  20. }
  21. }, "B 线程").start();
  22. new Thread(() ->{
  23. for (int i = 1; i <= 10; i++) {
  24. demoClass.printC(i);
  25. }
  26. }, "C 线程").start();
  27. }
  28. }

image.png