资源类

    1. package Test22_Demo.Demo08;/*
    2. @create 2020--12--15--15:18
    3. */
    4. /**
    5. * 资源类
    6. * 定义共享的数据,其中成员:name,sex
    7. */
    8. public class Person {
    9. //不使用private是为了便于后面的操作
    10. String name;
    11. String sex;
    12. public Person() {
    13. super();
    14. }
    15. }

    消费者目标对象

    1. package Test22_Demo.Demo08;/*
    2. @create 2020--12--15--15:29
    3. */
    4. /**
    5. * 消费者目标对象
    6. * 反复的获取Person对象并且打印
    7. */
    8. public class GetOut implements Runnable{
    9. //实例化共享资源
    10. private Person person;
    11. //构造函数
    12. public GetOut(Person person) {
    13. this.person = person;
    14. }
    15. @Override
    16. public void run() {
    17. //使用循环获取
    18. while (true) {
    19. //线程睡眠100毫秒
    20. try {
    21. Thread.sleep(100);
    22. } catch (InterruptedException e) {
    23. e.printStackTrace();
    24. }
    25. //获取实例
    26. String name = person.name;
    27. String sex = person.sex;
    28. System.out.println(person);
    29. System.out.println("消费了:"+ name+" "+sex);
    30. }
    31. }
    32. }

    生产者目标对象

    1. package Test22_Demo.Demo08;/*
    2. @create 2020--12--15--15:20
    3. */
    4. /**
    5. * 生产者
    6. * <p>
    7. * 生产者的执行目标:
    8. * 反复为Person对象赋值属性:Jack 男 与 Rose 女
    9. */
    10. public class putIn implements Runnable {
    11. //实例化对象
    12. private Person person;
    13. //创建构造方法用于接收外部传入的共享数据Person
    14. public putIn(Person person) {
    15. this.person = person;
    16. }
    17. @Override
    18. public void run() {
    19. //使用循环达到反复赋值的目的
    20. //如果是奇数就生成Jack 男 如果是偶数就生成rose 女
    21. int i = 0;
    22. while (true) {
    23. synchronized (person) {
    24. try {
    25. Thread.sleep(100);//每隔100毫秒
    26. } catch (InterruptedException e) {
    27. e.printStackTrace();
    28. }
    29. //判断生产的内容
    30. if (i % 2 == 1) {//男
    31. person.name = "Jack";
    32. person.sex = "男";
    33. } else {
    34. person.name = "Rose";
    35. person.sex = "女";
    36. }
    37. System.out.println(person);
    38. System.out.println("生产了"+person.name+"-"+person.sex);
    39. }
    40. i++;
    41. }
    42. }
    43. }

    演示等待唤醒机制

    1. package Test22_Demo.Demo08;/*
    2. @create 2020--12--15--15:15
    3. */
    4. /**
    5. *演示等待和唤醒机制
    6. *
    7. * 开启生产者和消费者的主要线程逻辑
    8. * 生产者和消费者的线程执行目标可以通过构造函数传入共同操作的同一个资源对象
    9. *
    10. * 生产者和消费者线程安全的问题:
    11. * 将生产过程和消费过程都使用synchronized包裹代码块,并且使用共享对象作为锁
    12. *
    13. */
    14. public class WaiteNotifyDemo {
    15. public static void main(String[] args) {
    16. //实例化对象
    17. Person person = new Person();
    18. //创建生产者的执行目标
    19. putIn putIn = new putIn(person);
    20. //创建消费者的执行目标
    21. GetOut getOut = new GetOut(person);
    22. //开启生产者线程
    23. Thread putInThread = new Thread(putIn);
    24. putInThread.start();
    25. //开启消费者线程
    26. Thread getOutThread = new Thread(getOut);
    27. getOutThread.start();
    28. }
    29. }
    • 解决方案:
    • 等待唤醒的操作
    1. 在person类中声明一个flag - 状态
    2. 在生产者的执行目标中,先判断是否有数据

      1. 有:生产者进入等待(wait)<br />没有:正常生产<br />标记:true<br />唤醒消费者
    3. 在消费者线程执行目标中先判断是否有数据:

    有:正常消费
    没有:等待生产(wait)
    标记:flase
    唤醒生产者
    补充
    sleep方法和wait方法是否都释放锁:

    1. sleep方法由于线程会自动苏醒,所以不释放锁
    2. wait方法释放锁,由其他的线程唤醒等待的这个线程,被唤醒后,会继续执行wait后面的代码

    **

    • object中两个方法:
    • 1.wait() - 进入等待
    • 2.notify() - 唤醒后进入可运行状态

    **

    唤醒和等待:
    资源类:

    1. package Test22_Demo.Demo09;/*
    2. @create 2020--12--15--15:18
    3. */
    4. /**
    5. * 资源类
    6. * 定义共享的数据,其中成员:name,sex
    7. */
    8. public class Person {
    9. //不使用private是为了便于后面的操作
    10. String name;
    11. String sex;
    12. //状态标记
    13. /**
    14. * flag:
    15. * true:有数据,生产者等待消费
    16. * false:没有数据,消费者等待
    17. */
    18. boolean flag;
    19. public Person() {
    20. super();
    21. }
    22. }

    消费者目标对象:

    1. package Test22_Demo.Demo09;/*
    2. @create 2020--12--15--15:29
    3. */
    4. /**
    5. * 消费者目标对象
    6. * 反复的获取Person对象并且打印
    7. */
    8. public class GetOut implements Runnable{
    9. //实例化共享资源
    10. private Person person;
    11. //构造函数
    12. public GetOut(Person person) {
    13. this.person = person;
    14. }
    15. @Override
    16. public void run() {
    17. //使用循环获取
    18. while (true) {
    19. //利用共享对象作为锁
    20. synchronized (person) {
    21. //获取判断状态
    22. while (!person.flag) {
    23. //没有数据就等待
    24. try {
    25. person.wait();
    26. } catch (InterruptedException e) {
    27. e.printStackTrace();
    28. }
    29. }
    30. //有数据或者是刚刚被唤醒
    31. try {
    32. Thread.sleep(100);
    33. } catch (InterruptedException e) {
    34. e.printStackTrace();
    35. }
    36. //进行获取操作
    37. String name = person.name;
    38. String sex = person.sex;
    39. System.out.println(person);
    40. System.out.println("消费了" + name + "-" + sex);
    41. //切换状态
    42. person.flag = false;
    43. //唤醒生产者,如果有就唤醒,如果没有就无需唤醒
    44. person.notify();
    45. }
    46. }
    47. }
    48. }

    生产者

    1. package Test22_Demo.Demo09;/*
    2. @create 2020--12--15--15:20
    3. */
    4. /**
    5. * 生产者
    6. * <p>
    7. * 生产者的执行目标:
    8. * 反复为Person对象赋值属性:Jack 男 与 Rose 女
    9. */
    10. public class putIn implements Runnable {
    11. //实例化对象
    12. private Person person;
    13. //创建构造方法用于接收外部传入的共享数据Person
    14. public putIn(Person person) {
    15. this.person = person;
    16. }
    17. @Override
    18. public void run() {
    19. //使用循环达到反复赋值的目的
    20. //如果是奇数就生成Jack 男 如果是偶数就生成rose 女
    21. int i = 0;
    22. while (true) {
    23. synchronized (person) {
    24. //判断状态flag
    25. while (person.flag) {
    26. //有数据,就等待
    27. try {
    28. person.wait();//线程阻塞
    29. } catch (InterruptedException e) {
    30. e.printStackTrace();
    31. }
    32. }
    33. //如果没有数据或者刚刚被唤醒
    34. //判断生产的内容
    35. if (i % 2 == 1) {//男
    36. person.name = "Jack";
    37. try {
    38. Thread.sleep(100);
    39. } catch (InterruptedException e) {
    40. e.printStackTrace();
    41. }
    42. person.sex = "男";
    43. } else {
    44. person.name = "Rose";
    45. try {
    46. Thread.sleep(100);
    47. } catch (InterruptedException e) {
    48. e.printStackTrace();
    49. }
    50. person.sex = "女";
    51. }
    52. System.out.println(person);
    53. System.out.println("生产了"+person.name+"-"+person.sex);
    54. //切换状态为true
    55. person.flag = true;
    56. //如果消费者等待,就唤醒消费者,如果没有消费者等待就无需唤醒,相当于没有执行
    57. person.notify();
    58. }
    59. i++;
    60. }
    61. }
    62. }

    等待和消费机制:

    1. package Test22_Demo.Demo09;/*
    2. @create 2020--12--15--15:15
    3. */
    4. /**
    5. *演示等待和唤醒机制
    6. *
    7. * 开启生产者和消费者的主要线程逻辑
    8. * 生产者和消费者的线程执行目标可以通过构造函数传入共同操作的同一个资源对象
    9. *
    10. * 生产者和消费者线程安全的问题:
    11. * 将生产过程和消费过程都使用synchronized包裹代码块,并且使用共享对象作为锁
    12. *
    13. *
    14. * 解决方案:
    15. * 等待唤醒的操作
    16. *
    17. * object中两个方法:
    18. * 1.wait() - 进入等待
    19. * 2.notify() - 唤醒后进入可运行状态
    20. */
    21. public class WaiteNotifyDemo {
    22. public static void main(String[] args) {
    23. //实例化对象
    24. Person person = new Person();
    25. //创建生产者的执行目标
    26. putIn putIn = new putIn(person);
    27. //创建消费者的执行目标
    28. GetOut getOut = new GetOut(person);
    29. //开启生产者线程
    30. Thread putInThread = new Thread(putIn);
    31. putInThread.start();
    32. //开启消费者线程
    33. Thread getOutThread = new Thread(getOut);
    34. getOutThread.start();
    35. }
    36. }

















    **