背景:.start()之后,线程并不是立即创建,线程也并非按顺序创建。若想让线程顺序创建,则需要了解线程间的通信,以及下一节线程间的定制化通信

线程间通信

线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模 型来实现的。我们来基本一道面试常见的题目来分析
对于之前的操作方法的编写可以进行细化,分为三步:判断、执行、通知
题目: 场景—-两个线程,一个线程对当前数值加 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. {
  12. DemoClass demoClass = new DemoClass();
  13. new Thread( () - > {
  14. for ( int i = 0; i < 5; i++ )
  15. {
  16. demoClass.increment();
  17. }
  18. }, "线程 A" ).start();
  19. new Thread( () - > {
  20. for ( int i = 0; i < 5; i++ )
  21. {
  22. demoClass.decrement();
  23. }
  24. }, "线程 B" ).start();
  25. }
  26. }
  27. package com.atguigu.test;
  28. class DemoClass {
  29. /* 加减对象 */
  30. private int number = 0;
  31. /**
  32. * 加 1
  33. */
  34. public synchronized void increment()
  35. {
  36. try {
  37. while ( number != 0 ) //判断
  38. {
  39. this.wait();
  40. }
  41. number++; //工作
  42. System.out.println( "--------" + Thread.currentThread().getName() + "加一成
  43. 功----------,值为:" + number );
  44. notifyAll(); //通知
  45. }catch ( Exception e ) {
  46. e.printStackTrace();
  47. }
  48. }
  49. /**
  50. * 减一
  51. */
  52. public synchronized void decrement()
  53. {
  54. try {
  55. while ( number == 0 ) //判断
  56. {
  57. this.wait();
  58. }
  59. number--; //工作
  60. System.out.println( "--------" + Thread.currentThread().getName() + "减一成
  61. 功----------,值为:" + number );
  62. notifyAll(); //通知
  63. }catch ( Exception e ) {
  64. e.printStackTrace();
  65. }
  66. }
  67. }

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. {
  17. try {
  18. lock.lock();
  19. while ( number != 0 ) //判断
  20. {
  21. condition.await();
  22. }
  23. number++; /工作
  24. System.out.println( "--------" + Thread.currentThread().getName() + "加一成
  25. 功----------,值为:" + number );
  26. condition.signalAll(); //通知
  27. }catch ( Exception e ) {
  28. e.printStackTrace();
  29. } finally {
  30. lock.unlock();
  31. }
  32. }
  33. /**
  34. * 减一
  35. */
  36. public void decrement()
  37. {
  38. try {
  39. lock.lock();
  40. while ( number == 0 )
  41. {
  42. condition.await();
  43. }
  44. number--;
  45. System.out.println( "--------" + Thread.currentThread().getName() + "减一成
  46. 功----------,值为:" + number );
  47. condition.signalAll();
  48. }catch ( Exception e ) {
  49. e.printStackTrace();
  50. } finally {
  51. lock.unlock()
  52. }
  53. }
  54. }

wait()虚假判断

问题来源于wait()在哪里睡就会在哪里醒。当在判断和工作之间睡就会在此醒,这样就会让之前的判断失效,造成虚假判断。
所以把判断从if改为while,这样即使睡醒也要再参与判断,不会继续执行image.png