开发者

Java Thread多线程开发中Object类详细讲解

开发者 https://www.devze.com 2023-03-02 10:55 出处:网络 作者: 健鑫.
目录方法概览Threadwait  notify notifyAll方法详解作用阻塞阶段唤醒阶段遇到中断代码展示特点通过wait notify方法实现生产者和消费者sleep方法详解sleep不会释放锁sleep响应中断总结join方法详解代码展示yield
目录
  • 方法概览
    • Thread
  • wait  notify notifyAll方法详解
    • 作用
      • 阻塞阶段
      • 唤醒阶段
      • 遇到中断
    • 代码展示
      • 特点
        • 通过wait notify方法实现生产者和消费者
        • sleep方法详解
          • sleep不会释放锁
            • sleep响应中断
              • 总结
              • join方法详解
                • 代码展示
                • yield方法

                  方法概览

                  Thread

                  Java Thread多线程开发中Object类详细讲解

                  wait  notify notifyAll方法详解

                  作用

                  阻塞阶段

                  使用了wait方法之后,线程就会进入阻塞阶段,只有发生以下四种情况中的其中一个,线程才会被唤醒

                  • 另一个线程调用了这个线程的notify方法,刚好唤醒的是本线程
                  • 另一个线程调用了这个对象的notifyAll方法
                  • 过了wait规定的超时时间
                  • 线程调用了interrupt

                  唤醒阶段

                  notify会唤醒单个处于阻塞python状态的线程,唤醒的线程是随机的

                  notify和wait都需要写在synchronized代码块里,不然会抛出异常

                  notifyAll会唤醒所有等待的线程

                  遇到中断

                  执行wait方法之后,被中断,会抛出InterruptedException这个异常

                  代码展示

                  • 展示wait和notify的基本用法
                  • 该代码执行wait方法之后会释放锁,然后thread2执行notify方法
                  • notify方法执行完毕之后,并没有立即释放锁,而是接着执行之后的代码,也就是打印“Thread2调用notify”这句话
                  • thread2执行完毕之后,会进行释放锁,thread1才会继续执行
                  • 在此期间,thread1虽然被唤醒,但是一直在等待thread2同步代码块里面的代码执行完毕
                  public class Wait {
                      public static void main(String[] args) throws InterruptedException {
                          Thread1 thread1 = new Thread1();
                          Thread2 thread2 = new Thread2();
                          thread1.start();
                          Thread.sleep(200);
                          thread2.start();
                      }
                      public static Object object = new Object();
                      static class Thread1 extends Thread {
                          @Override
                          public void run() {
                              synchronized (object) {
                                  System.out.println("Thread1执行");
                                  try {
                                      object.wait();
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                                  System.out.println("Thread1获取锁");
                              }
                          }
                      }
                      static class Thread2 extends Thread {
                          @Override
                          public void run() {
                              synchronized (object) {
                                  object.notify();
                                  System.out.println("Thread2调用notify");
                              }
                          }
                      }
                  }
                  /*
                  Thread1执行
                  Thread2调用notify
                  Thread1获取锁
                  * */
                  
                  • notify和notifyAll的展示
                  • 第一个输出:threadc调用notifyAll
                  • 第二个输出:threadc调用notify
                  • 调用notify的时候,程序并没有结束,threadb陷入等待
                  public class notifyOrAll implements Runnable{
                      private static final Object a = new Object();
                      public static void main(String[] args) throws InterruandroidptedException {
                          Runnable r = new notifyOrAll();
                          Thread threada = new Thread(r);
                          Thread threadb = new Thread(r);
                          Thread threadc = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  synchronized (a) {
                  //                    a.notifyAll();
                                      a.notify();
                                      System.out.println(Thread.currentThread().getName() + "notify");
                                  }
                              }
                          });
                          threada.start();
                          Thread.sleep(200);
                          threadb.start();
                          Thread.phpsleep(200);
                          threadc.start();
                      }
                      @Override
                      public void run() {
                          synchronized (a) {
                              System.out.println(Thread.currentThread().getName() + "得到锁");
                              try {
                                  System.out.println(Thread.currentThread().getName() + "wait");
                                  a.wait();
                                  System.out.println(Thread.currentThread().getName() + "wait结束");
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                      }
                  }
                  /*
                  Thread-0得到锁
                  Thread-0wait
                  Thread-1得到锁
                  Thread-1wait
                  Thread-2notifyAll
                  Thread-1wait结束
                  Thread-0wait结束
                  * */
                  /*
                  Thread-0得到锁
                  Thread-0wait
                  Thread-1得到锁
                  Thread-1wait
                  Thread-2notify
                  Thread-0wait结束
                  * */
                  • 只释放当前monitor
                  • 证明wait只释放当前的那把锁
                  public class OwnMonitor {
                      private static volatile Object a = new Object();
                      private static volatile Object b = new Object();
                      public static void main(String[] args) throws InterruptedException {
                          Thread threadA = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  synchronized (a) {
                                      System.out.println("threadA得到a");
                                      synchronized (b) {
                                          System.out.println("threadA得到锁b");
                  
                                          try {
                                              System.out.println("threadA释放a");
                                              a.wait();
                                          } catch (InterruptedException e) {
                                              e.printStackTrace();
                                          }
                                      }
                                  }
                              }
                          });
                          Thread threadB = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  synchronized (a) {
                                      System.out.println("threadB得到a");
                                      System.out.println("threadB要获取b");
                                      synchronized (b) {
                                          System.out.println("threadB得到b");
                                      }
                                  }
                              }
                          });
                          threadA.start();
                          Thread.sleep(1000);
                          threadB.start();
                      }
                  }
                  /*
                  threadA得到a
                  threadA得到锁b
                  threadA释放a
                  threadB得到a
                  threadB要获取b
                  * */
                  

                  特点

                  • 执行这些方法必须先获取锁
                  • notify只能换取一个,而且是随机的
                  • 都属于Object。任何对象都可以调用
                  • 都是native final修饰的

                  当线程从wait状态刚被唤醒时,通常不能直接得到锁,那就会从waiting状态转换到blocked状态,抢到锁之后状态转变为runnable

                  如果发生异常,则直接跳到Terminated状态

                  通过wait notify方法实现生产者和消费者

                  • 将storge当作生产者和消费者进行工作的仓库
                  • 如果storge中没有数据,生产者就开始wait
                  • 如果storge中数据满了,消费者就开始wait
                  • 生产者和消费者每进行一次生产和消费,就执行notify
                  public class ProducerConsumer {
                      public static void main(String[] args) {
                          Storge storge = new Storge();
                          Producer producer = new Producer(storge);
                          Consumer consumer = new Consumer(storge);
                          new Thread(producer).start();
                          new Thread(consumer).start();
                      }
                  }
                  class Producer implements Runnable {
                      private Storge storge;
                      public Producer(Storge storge) {
                          this.storge = storge;
                      }
                      @Override
                      public void run() {
                          for (int i = 0; i < 100; i++) {
                              storge.put();
                          }
                      }
                  }
                  class Consumer implements Runnable {
                      private Storge storge;
                      public Consumer(Storge storge) {
                          this.storge = storge;
                      }
                      @Override
                      public void run() {
                          for (int i = 0; i < 100; i++) {
                              storge.take();
                          }
                      }
                  }
                  class Storge {
                      private int maxSize;
                      private LinkedList<Date> storge;
                      public Storge() {
                          maxSize = 10;
                          storge = new LinkedList<>();
                      }
                      public synchronized void put() {
                          while (storge.size() == maxSize) {
                              try {
                                  wait();
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                          storge.add(new Date());
                          System.out.println("已经有了" + storge.size());
                          notify();
                      }
                      public synchronized void take() {
                          while (storge.size() == 0) {
                              try {
                                  wait();
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                          System.out.println("拿到了" + storge.poll() + "还剩" + storge.size());
                          notify();
                      }
                  }
                  

                  sleep方法详解

                  作用:让线程在预期的时间执行,其他时间不占用CPU资源

                  特点:和wait不一样,sleep不释放锁

                  sleep不会释放锁

                  证明sleep不会释放 synchronized锁

                  public class SleepSyn implements Runnable{
                      public static void main(String[] args) {
                          SleepSyn sleepSyn = new SleepSyn();
                          new Thread(sleepSyn).start();
                          new Thread(sleepSyn).start();
                      }
                      @Override
                      public void run() {
                          syn();
                      }
                      private synchronized void syn() {
                          System.out.println(Thread.currentThread().getName() + "获取锁");
                          try {
                              Thread.sleep(2000);
                          } catch (InterruptedException e) {
                              phpe.printStackTrace();
                          }
                          System.out.println(Thread.currentThread().getName() + "释放锁");
                      }
                  }
                  /*
                  * Thread-0获取锁
                  Thread-0释放锁
                  Thread-1获取锁
                  Thread-1释放锁
                  * */
                  

                  证明sleep不释放Lock锁

                  public class sleepLock implements Runnable{
                      private static final Lock LOCK = new ReentrantLock();
                      @Override
                      public void run() {
                          LOCK.lock();
                          System.out.println(Thread.currentThread().getName() + "获取锁");
                          try {
                              Thread.sleep(2000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          } finally {
                              LOCK.unlock();
                          }
                          System.out.println(Thread.currentThread().getName() + "释放锁");
                      }
                      public static void main(String[] args) {
                          sleepLock sleepLock = new sleepLock();
                          new Thread(sleepLock).start();
                          new Thread(sleepLock).start();
                      }
                  }
                  /*
                  * Thread-0获取锁
                  Thread-0释放锁
                  Thread-1获取锁
                  Thread-1释放锁
                  * */
                  

                  sleep响应中断

                  • 抛出InterruptedException
                  • 会清除中断状态
                  • 中断之后,抛出异常继续执行
                  public class sleepInterrupted implements Runnable{
                      public static void main(String[] args) throws InterruptedException {
                          Thread thread = new Thread(new sleepInterrupted());
                          thread.start();
                          Thread.sleep(2000);
                          thread.interrupt();
                      }
                      @Override
                      public void run() {
                          for (int i = 0; i < 10; i++) {
                              System.out.println(new Date());
                              try {
                                  TimeUnit.SECONDS.sleep(1);
                              } catch (InterruptedException e) {
                                  System.out.println("中断");
                                  e.printStackTrace();
                              }
                          }
                      }
                  }
                  /*
                  * Fri Jan 27 21:11:57 CST 2023
                  Fri Jan 27 21:11:58 CST 2023
                  中断
                  Fri Jan 27 21:11:59 CST 2023
                  Java.lang.InterruptedException: sleep interrupted
                     at java.lang.Thread.sleep(Native Method)
                     at java.lang.Thread.sleep(Thread.java:340)
                     at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
                     at com.jx.JavaTest.ThreadObjectMethod.sleepInterrupted.run(sleepInterrupted.java:21)
                     at java.lang.Thread.run(Thread.java:748)
                  Fri Jan 27 21:12:00 CST 2023
                  Fri Jan 27 21:12:01 CST 2023
                  Fri Jan 27 21:12:02 CST 2023
                  Fri Jan 27 21:12:03 CST 2023
                  Fri Jan 27 21:12:04 CST 2023
                  Fri Jan 27 21:12:05 CST 2023
                  Fri Jan 27 21:12:06 CST 2023
                  Process finished with exit code 0
                  * */

                  总结

                  sleep方法可以让线程进入waiting状态,不占用CPU资源,但是不释放锁,规定时间之后再运行

                  休眠期间如果被打断,会抛出异常并清除中断状态

                  join方法详解

                  新线程加入,主线程等子线程执行完毕

                  代码展示

                  • 前一个结果是使用join
                  • 后一个结果是没使用join
                  • 可知使用join之后,主线程会等join的线程执行完毕再继续执行
                  public class join {
                      public static void main(String[] args) throws InterruptedException {
                          Thread thread1 = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  try {
                                      Thread.sleep(1000);
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                                  System.out.println(Thread.currentThread().getName() + "执行完毕");
                              }
                          });
                          Thread thread2 = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  try {
                                      Thread.sleep(1000);
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                                  System.out.println(Thread.currentThread().getName() + "执行完毕");
                              }
                          });
                          thread1.start();
                          thread2.start();
                          System.out.println("开始等待子线程运行");
                  //        thread1.join();
                  //        thread2.join();
                          System.out.println("所有线程执行完毕");
                      }
                  }
                  /*
                  * 开始等待子线程运行
                  Thread-0执行完毕
                  Thread-1执行完毕
                  所有线程执行完毕
                  * */
                  /*
                  * 开始等待子线程运行
                  所有线程执行完毕
                  Thread-1执行完毕
                  Thread-0执行完毕
                  * */
                  • 遇到中断
                  • 第一个的运行结果是主线程没中断的打印结果
                  • 第二个的运行结果是join期间进行中断的打印结果,可知在打印了“子线程运行完毕”之后,依然打印了“启动”两个字,可知会造成运行混乱
                  • 可以在捕获异常的代码块中,将join的线程也中断,可以解决上面的问题
                  public class joinInterrupt {
                      public static void main(String[] args) {
                          Thread main1 = Thread.currentThread();
                          Thread thread1 = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  try {
                                      main1.interrupt();
                                      Thread.sleep(2000);
                                      System.out.println("启动");
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                              }
                          });
                          thread1.start();
                          System.out.println("join");
                          try {
                              thread1.join();
                          } catch (InterruptedException e) {
                              System.out.println(Thread.currentThread().getName() + "中断");
                              // thread1.interrupt();
                              e.printStackTrace();
                          }
                          System.out.println("子线程运行完毕");
                      }
                  }
                  /*
                  * join
                  启动
                  子线程运行完毕
                  * */
                  /*
                  * join
                  maiandroidn中断
                  子线程运行完毕
                  java.lang.InterruptedException
                     at java.lang.Object.wait(Native Method)
                     at java.lang.Thread.join(Thread.java:1252)
                     at java.lang.Thread.join(Thread.java:1326)
                     at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt.main(joinInterrupt.java:23)
                  启动
                  Process finished with exit code 0
                  * */
                  /*
                  * join
                  main中断
                  子线程运行完毕
                  java.lang.InterruptedException: sleep interrupted
                     at java.lang.Thread.sleep(Native Method)
                     at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt$1.run(joinInterrupt.java:13)
                     at java.lang.Thread.run(Thread.java:748)
                  java.lang.InterruptedException
                     at java.lang.Object.wait(Native Method)
                     at java.lang.Thread.join(Thread.java:1252)
                     at java.lang.Thread.join(Thread.java:1326)
                     at com.jx.JavaTest.ThreadObjec开发者_Go培训tMethod.joinInterrupt.main(joinInterrupt.java:23)
                  Process finished with exit code 0
                  * */

                  join期间,线程处于WAITING状态

                  public class joinStates {
                      public static void main(String[] args) throws InterruptedException {
                          Thread main1 = Thread.currentThread();
                          Thread thread = new Thread(new Runnable() {
                              @Override
                              public void run() {
                                  try {
                                      Thread.sleep(3000);
                                      System.out.println(main1.getState());
                                      System.out.println("子线程运行结束");
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                              }
                          });
                          thread.start();
                          System.out.println("join");
                          thread.join();
                          System.out.println("运行完毕");
                      }
                  }
                  /*
                  * join
                  WAITING
                  子线程运行结束
                  运行完毕
                  * */
                  

                  yield方法

                  用来释放CPU时间片,但是不一定能达到预期的效果,因为有时CPU资源不紧张,无需yield

                  和sleep的区别是:sleep期间不会被再次调度但是yield会立刻处于竞争状态,还会随时再次被调度

                  到此这篇关于Java Thread多线程开发中Object类详细讲解的文章就介绍到这了,更多相关Java Object类内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

                  0

                  精彩评论

                  暂无评论...
                  验证码 换一张
                  取 消

                  关注公众号