多线程---wait()与notify()的学习

 

 

 

 

wait()与notify()的使用

package com.mokuiran.thread.pcquestion;

//wait()的使用
public class WaitTest {
   public static void main(String[] args) {
       String text = "test";   //定义一个字符串作为锁对象
       String anthor = "hello";
       System.out.println("准备前。。。");
       synchronized (text){
           try {
               System.out.println("同步代码块wait之前。。。");
//               anthor.wait();//报错java.lang.IllegalMonitorStateException,因为锁对象调用
               text.wait();//线程一直等待,锁对象被释放,直到被唤醒
               System.out.println("同步代码块wait之后。。。");
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
       System.out.println("main后面的其余方法。。。");
  }
}

package com.mokuiran.thread.pcquestion;


//wait()与notify()的使用1
public class WNTest {
   public static void main(String[] args) {
       String lock = "test";   //定义一个字符串作为锁的对象

       Thread t1 = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (lock){
                   System.out.println("线程1开始等待:"+System.currentTimeMillis());
                   try {
                       lock.wait();
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println("线程1开始结束:"+System.currentTimeMillis());
              }
          }
      });

       //定义第二线程,在第二个线程中唤醒第一个线程
       Thread t2 = new Thread(new Runnable() {
           @Override
           public void run() {
               //notify()方法也需要在同步代码块中,有锁对象调用
               synchronized (lock){
                   System.out.println("线程2开始唤醒:"+System.currentTimeMillis());
                   lock.notify();  //唤醒在lock锁对象上等待的某一个线程
                   System.out.println("线程2结束唤醒:"+System.currentTimeMillis());
              }
          }
      });


       t1.start();

       try {
           Thread.sleep(3000); //main线程睡眠3秒,确保t1入睡
      } catch (InterruptedException e) {
           e.printStackTrace();
      }

       t2.start();
  }
}

package com.mokuiran.thread.pcquestion;

import java.util.ArrayList;
import java.util.List;

//wait()与notify()的使用2
public class WNTest2 {
   public static void main(String[] args) {
       //定义一个List存储String数据
       List<String> list = new ArrayList<>();

       //定义第一个线程,当list集合中元素数量不等于5时线程等待
       Thread t1 = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (list){
                   if (list.size()!=5){
                       System.out.println("线程1开始等待:"+System.currentTimeMillis());
                       try {
                           list.wait();
                      } catch (InterruptedException e) {
                           e.printStackTrace();
                      }
                       System.out.println("线程1被唤醒:"+System.currentTimeMillis());
                  }
              }
          }
      });

       //定义第二个线程,向list集合中添加元素
       Thread t2 = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (list){
                   for (int i = 0; i< 10;i++){
                       list.add("data--"+i);
                       System.out.println("线程2添加了第"+(i+1)+"个数据");
                       //判断元素的数量是否满足唤醒线程1
                       if (list.size()==5){
                           list.notify();
                           System.out.println("线程2发起唤醒通知");
                      }
                       try {
                           Thread.sleep(1000);
                      } catch (InterruptedException e) {
                           e.printStackTrace();
                      }
                  }
              }

          }
      });

       t1.start();

       try {
           //为了确保线程2在线程1之后开启,即让线程1先睡眠
           Thread.sleep(1000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }

       t2.start();
  }
}

Interrupt()方法会中断wait()

当线程处于wait()等待状态时,调用线程对象的interrupt()方法会中断线程的等待状态,会产生异常

package com.mokuiran.thread.pcquestion;

//测试interrupt()方法
public class InterruptTest {
   public static void main(String[] args) {
       SubThread t = new SubThread();
       t.start();

       try {
           Thread.sleep(1000); //主线程睡眠2秒,确保子线程处于Wait等待状态
           t.interrupt();
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
  }

   private static final Object Lock = new Object();//定义常量作为锁对象
   static class SubThread  extends Thread{
       @Override
       public void run() {
           synchronized (Lock){
               System.out.println("begin wait...");
               try {
                   Lock.wait();
                   System.out.println("end wait...");
              } catch (InterruptedException e) {
                   System.out.println("wait等待被中断了。。。");
              }
          }
      }
  }
}

 

wait(long)方法

package com.mokuiran.thread.demo;


//测试notify()方法以及wait(long)方法
//wait(long)带有long类型参数的wait()等待,如果在参数指定的时间内没有被唤醒,超时后会自动唤醒

public class Test{
   public static void main(String[] args) throws InterruptedException {
       Object lock = new Object();        //定义一个对象作为子线程的锁对象
       SubThread t1 = new SubThread(lock);
       SubThread t2 = new SubThread(lock);
       SubThread t3 = new SubThread(lock);


       new Thread(t1,"1").start();
       new Thread(t2,"2").start();
       new Thread(t3,"3").start();

       Thread.sleep(1000);

       synchronized (lock){
//           lock.notify();
           /*只能随机唤醒其中一个线程,其他等待的线程依然处于等待状态,对于处于等待状态的线程来说,
            错过了通知信号,这种现象也成为信号丢失*/
           lock.notifyAll();   //唤醒所有线程
      }

  }



   public static class SubThread extends Thread{
       private Object lock;    //定义实际变量作为锁的对象

       public SubThread(Object lock) {
           this.lock = lock;
      }
       @Override
       public void run() {
           synchronized (lock){
               System.out.println(Thread.currentThread().getName()+"-->wait等待之前。。。");
               try {
//                   lock.wait(5000);   //如果5000毫秒内没有被唤醒,则自动唤醒
                   lock.wait();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
               System.out.println(Thread.currentThread().getName()+"-->>>>wait等待之后。。。");
          }
      }
  }
}

 

通知过早的情况

package com.mokuiran.thread.demo;


public class Test {
   static boolean flag = true;

   public static void main(String[] args) {
       Object lock = new Object();

       Thread t1 = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (lock) {
                   while (flag) {
                       System.out.println("wait...before...");
                       try {
                           lock.wait();
                      } catch (InterruptedException e) {
                           e.printStackTrace();
                      }
                       System.out.println("wait...after...");
                  }
              }
          }
      });


       Thread t2 = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (lock) {
                   System.out.println("notify...before...");
                   lock.notify();
                   System.out.println("notify...after...");
                   flag = false;
              }
          }
      });

         /*如果先开启t1,再开启t2线程,大多数情况下,t1先等待,t2再把t1唤醒*/
//       t1.start();
//       t2.start();
     
       t2.start();
       t1.start();
       //如果先开启t2通知线程,在开启t1等待线程,可能会出现t1线程等待没有收到唤醒通知的情况
       
       //在当前示例当中,t1等待后让t2线程唤醒,如果t2线程先唤醒,就不让t1线程等待了,因此,本例当中
       /*最终输出为:        
notify...before...
notify...after...
   */
  }
}

 

wait条件发生了变化

package com.mokuiran.thread.demo;


import java.util.ArrayList;
import java.util.List;

public class Test{
   public static void main(String[] args) {
       //定义添加数据的线程对象
       ThreadAdd threadAdd = new ThreadAdd();
       //定义取数据的线程对象
       ThreadSubtract threadSubtract = new ThreadSubtract();
       threadSubtract.setName("sub1-->");

       //测试一:先开启添加数据线程,再开启取数据线程,大多数情况下都会正常取数据
//       threadAdd.start();
//       threadSubtract.start();
       //测试二:先开启取数据的线程,再开启添加数据的线程,取数据的线程会先等待,等到添加数据之后,再取数据
//       threadSubtract.start();
//       threadAdd.start();

       //测试三:开启两个取数据的线程,再开启添加数据的线程
       ThreadSubtract threadSubtract2 = new ThreadSubtract();
       threadSubtract2.setName("sub2-->");
       threadSubtract.start();
       threadSubtract2.start();
       threadAdd.start();
       /*
       第三次测试的某一次结果如下:
       sub1--> begin wait...
       sub2-->从集合中取了data后,集合中数据的数量:0
       sub1--> end wait...
       Exception in thread "sub1-->" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
       分析可能的执行顺序:
               threadSubtract线程先启动,取数据时,集合中没有数据,wait()等待
               threadAdd线程获得CPU执行权,添加数据,把threadSubtract线程唤醒
               threadSubtract2线程开启后获得CPU执行权,正常取数据
               threadSubtract线程获得CPU执行权,打印end wait。。。,然后再执行list.remove(0)取数据时,现再
               list集合中已经没有数据了,这时产生java.lang.IndexOutOfBoundsException异常

               出现异常的原因:向list集合中添加了一个数据,却remove了两次

               如何解决?
                   答:将判断条件中的if改为while
        */

  }
   //1.定义List集合
   static List list = new ArrayList<>();

   //2.定义方法从集合中取数据
   public static void subtract(){
       synchronized (list){
//           if (list.size() == 0){
           while (list.size() == 0){
               try {
                   System.out.println(Thread.currentThread().getName()+" begin wait...");
                   list.wait();
                   System.out.println(Thread.currentThread().getName()+" end wait...");
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           Object data = list.remove(0);   //从集合中取(移除)一个数据
           System.out.println(Thread.currentThread().getName()+"从集合中取了"+data+"后,集合中数据的数量:"+list.size());
      }
  }

   //3.定义方法向集合中添加数据后,通知等待的线程取数据
   public static void addtest(){
       synchronized (list){
           list.add("data");
           list.notifyAll();
      }
  }

   //4.定义线程类共调用add()取数据的方法
   static class ThreadAdd extends Thread{
       @Override
       public void run() {
           addtest();
      }
  }

   //5.定义线程类调用subtract()方法
   static class ThreadSubtract extends Thread{
       @Override
       public void run() {
           subtract();
      }
  }
}
posted @   默夔然  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示