线程的通信

涉及到的三个方法:

(1)wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器

(2)notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的那个

(3)notifyAll():一旦执行此方法,就会唤醒被wait的所有线程

说明:

(1)wait(),notify(,notifyAll()三个方法必须使用在同步代码块或同步方法中

(2)wait(),notify(,notifyAll()三个方法的调用者必须是同步代码块或者同步方法中的同步监视器,否则出现异常

(3)wait(),notify(,notifyAll()三个方法是定义在java.long.Object类中

  1. package thread_communicate;
  2. public class thread_com {
  3. public static void main(String[] args) {
  4. number n=new number();
  5. Thread t1=new Thread(n);
  6. Thread t2=new Thread(n);
  7. t1.setName("线程1");
  8. t2.setName("线程2");
  9. t1.start();
  10. t2.start();
  11. }
  12. }
  13. class number implements Runnable{
  14. private int num=1;
  15. @Override
  16. public void run() {
  17. while(true){
  18. synchronized(this){
  19. notify();
  20. if(num<=100){
  21. try {
  22. Thread.sleep(10);
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. System.out.println(Thread.currentThread().getName()+":"+num);
  27. num++;
  28. try {
  29. wait();
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }else{
  34. break;
  35. }
  36. }
  37. }
  38. }
  39. }

sleep()和wait()方法的异同点:

1.相同点:一旦执行,都可使当前线程进入阻塞状态

2.不同点:(1)两个方法声明的位置不同:Thread类声明sleep,Object类声明wait

  1. 2)调用范围不同:sleep可以在任何需要的场景下调用,wait必须在同步代码块或同步方法中
  2. 3)关于是否释放同步监视器:如果两个方法都在同步代码块或同步方法中,sleep不会释放同步监视器,而wait()会释放同步监视器

线程通信的应用:经典例题 :生产者/消费者问题

  1. 生产者将产品交给店员,消费者从店员取走产品,店员一次只能持有固定数量的产品;
  2. 如果生产者试图生产更多的产品,店员会叫生产者停下,如果店中有空位放产品了再通知生产者继续生产;
  3. 如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
  4. package produce_cunsume;
  5. public class p_c {
  6. public static void main(String[] args) {
  7. clerk c=new clerk();
  8. producer pro=new producer(c);
  9. consumer con=new consumer(c);
  10. pro.setName("生产者");
  11. con.setName("消费者");
  12. pro.start();
  13. con.start();
  14. }
  15. }
  16. class clerk{
  17. private int product=0;
  18. public synchronized void pro_product(){
  19. if(product<20) {
  20. product++;
  21. System.out.println(Thread.currentThread().getName() + "开始生产第" + product + "个产品");
  22. notify();
  23. }else{
  24. try {
  25. wait();
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. public synchronized void con_product(){
  32. if(product>0){
  33. System.out.println(Thread.currentThread().getName()+"开始消费第"+product+"个产品");
  34. product--;
  35. notify();
  36. }else{
  37. try {
  38. wait();
  39. } catch (InterruptedException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. }
  44. }
  45. class producer extends Thread {
  46. private clerk c;
  47. public producer(clerk c) {
  48. this.c = c;
  49. }
  50. @Override
  51. public void run() {
  52. System.out.println(getName()+"生产者开始生产...");
  53. while(true){
  54. try {
  55. sleep(10);
  56. } catch (InterruptedException e) {
  57. e.printStackTrace();
  58. }
  59. c.pro_product();
  60. }
  61. }
  62. }
  63. class consumer extends Thread{
  64. private clerk c;
  65. public consumer(clerk c){
  66. this.c=c;
  67. }
  68. @Override
  69. public void run() {
  70. System.out.println(getName()+"消费者开始消费...");
  71. while(true){
  72. try {
  73. sleep(10);
  74. } catch (InterruptedException e) {
  75. e.printStackTrace();
  76. }
  77. c.con_product();
  78. }
  79. }
  80. }