美文网首页程序员
Java线程生命周期和锁的简单使用

Java线程生命周期和锁的简单使用

作者: lantao_js | 来源:发表于2019-08-14 17:00 被阅读0次

    本文介绍了java线程的生命周期,Synchronized的几个方法简单的使用。

    线程生命周期

    • 初始状态(New)

      New Thread之后,
       

    • 就绪状态(Ready)

      表示获取到了Cpu的执行时间片,也就是cpu的执行权,等待开始执行。
       

    • 运行状态(Runable)

      执行start之后,开始运行。
       

    • 阻塞状态(Blocked)

      在进入synchronized的临界区或者Lock的临界区,等待获取监视器(monitor)锁,线程会进入同步队列(SynchronizedQueue)中。
       

    • 等待状态:(Waiting)

      在执行await(),wait(),jion(),LockSupport.park()方法进入等待状态;
       

    • 等待超时状态

      在执行Object.await(time), Object.wait(time), Object.sellp(time), LockSupport.parkUntil,lockSupport.parkNanos 进入等待超时状态。
       

    • 终止状态

      线程执行完毕或者执行了Thread.interrupt() / Thread.stop(),不建议使用的Thread.stop() 因为 Thread.stop是直接强行结束,不会释放资源

    • 配图

      线程生命周期.png

    锁的几个简单方法

    • wait 和 notify/notifyAll

      解释

      wait: 将线程状态置位 '等待状态',进入等待队列等待。
      notify/notifyAll: notify是随机唤醒一个线程进入 '同步队列',notifyAll是唤醒全部被监视器锁wait的线程进入 '同步队列',等待获取监视器锁后继续执行。

      提示:wait,notify/notifyAll都需要在获取到监视器所(monitor)后才可以进行操作。

      代码
      public class WaitAndNotifyTest {
      
          private static Object obj = new Object();
      
          public static void main(String[] args) {
              // 创建线程 thread1
              Thread thread1 = new Thread(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          System.out.println(Thread.currentThread().getName() + "   begin wait...");
                          synchronized (obj) {
                              obj.wait();
                          }
                          System.out.println(Thread.currentThread().getName() + "   end wait...");
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
              }, "thread1");
      
              // 创建线程 thread2
              Thread thread2 = new Thread(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          System.out.println(Thread.currentThread().getName() + "   begin wait...");
                          synchronized (obj) {
                              obj.wait();
                          }
                          System.out.println(Thread.currentThread().getName() + "   end wait...");
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
              }, "thread2");
      
      
      
              // 启动
              thread1.start();
              thread2.start();
      
              try {
                  // 睡眠一秒
                  Thread.sleep(1000L);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
      
              // 下面我们加上 obj.notify() 就会先输出 begin wait  然后sellp 10秒,执行obj.notify() 唤醒 thread1 线程 , 输出end wait
              // obj 上可能会存在wait 多个线程, notify唤醒是随机的,不一定能唤醒哪一个线程
              // 如果调用 notify 的线程未获取 对象锁,在调用 notify 的时候会抛出 java.lang.IllegalMonitorStateException 异常
              synchronized (obj) {
                  // 唤醒 使用呢 obj 调用 wait 方法的其中一个线程 (随机)
                  obj.notify();
                  // 唤醒 使用呢 obj 调用 wait 方法的所有线程
                  obj.notifyAll();
              }
          }
      }
      
      执行结果:
      thread2   begin wait...
      thread1   begin wait...
      thread1   end wait...
      thread2   end wait...
      
    • await,signal/signalAll

      解释

      await,signal/signalAll方法是Lock Condition的方法,语义和Object的wait,notify/notifyAll是完全相同的。

      代码
      /**
       * @Auther: lantao
       * @Date: 2019-04-15 14:49
       * @Company:
       * @maill:
       * @Description: Condition 条件 有 singal signalAll 和 await 方法 和Object 的 notify notifyAll 和 wait 是一个意思同样会释放锁  执行singal和notify的时候也需要在等待获取锁
       */
              public class LockCondition {
      
                  public static ReentrantLock lock = new ReentrantLock();
      
                  public static Condition a = lock.newCondition();
      
                  public static void main(String[] args) throws InterruptedException {
                      Runnable runnable = () -> {
                          try {
                              lock.lock();
                              System.out.println(Thread.currentThread().getName());
                              System.out.println("1");
                              a.await();
      
                              System.out.println(Thread.currentThread().getName() + "被唤醒了");
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }finally {
                              lock.unlock();
                          }
                      };
      
                      Runnable runnable1 = () -> {
                          try {
                              lock.lock();
                              System.out.println("线程" +Thread.currentThread().getName() + "开始执行sinal");
                              a.signalAll();
                          } catch (Exception e) {
                              e.printStackTrace();
                          }finally {
                              lock.unlock();
                          }
                      };
      
                      new Thread(runnable,"Thread1").start();
                      new Thread(runnable,"Thread2").start();
                      Thread.sleep(100);
                      new Thread(runnable1,"Thread3").start();
                  }
              }
      
      执行结果:
      Thread1
      Thread2
      线程Thread3开始执行sinal
      Thread1被唤醒了
      Thread2被唤醒了
      
    • Join 和 Join(time)

      解释

      等待调用Join的线程执行完成后再继续执行,或者等待时间超过了超时时间继续执行

      代码
      /**
       * @Auther: lantao
       * @Date:
       * @Company:
       * @maill:
       * @Description: Join 核心是等待指定线程运行完后再继续运行  Join(time) 就是等待线程执行的一个超时时间 超过了就继续执行了
       */
              public class JoinTest {
                  public static void main(String[] args) throws InterruptedException {
                      Thread thread1 = new Thread(new Runnable() {
                          @Override
                          public void run() {
                              System.out.println("1");
                              try {
                                  Thread.sleep(2000L);
                                  System.out.println("正常完成");
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                              System.out.println("2");
                          }
                      });
      
                      thread1.start();
      
                      // 执行 jion 等待线程 thread1 执行完后再继续执行
                      thread1.join();
      //        thread1.join(1000);
      
                      // 这样最终执行的顺序是 1 2 3  如果不增加 thread1.join() 结果可能是 312 也可能是 132
                      // Join 核心是等待指定线程运行完后再继续运行
                      System.out.println("3");
                  }
              }
      
      执行结果:
      1
      正常完成
      2
      3
      
    • yield

      解释

      yeid 方法的核心是让出 cpu 时间片 ,也就是cpu执行权,线程会直接进入就绪状态,线程调度器会从线程就绪队列里获取一个线程优先级最高的线程来执行,当然也有可能直接会去到刚刚让出cpu执行权的线程,继续执行yield 后续的代码。

      代码
      /**
       * @Auther: lantao
       * @Date: 2019-03-25 17:20
       * @Company:
       * @maill:
       * @Description:
       */
              public class YieldTest {
      
                  private static Object obj = new Object();
      
      
                  public static void main(String[] args) {
                      Thread thread1 = new Thread(new Runnable() {
                          @Override
                          public void run() {
                              for (int i = 0; i <= 5; i++) {
      
                                  if (0 / 5 == i) {
                                      System.out.println(Thread.currentThread().getName() + "   开始执行 yield ");
                                      Thread.yield();
                                      System.out.println("trhead1");
                                  }
                              }
                          }
                      }, "thread1");
                      Thread thread2 = new Thread(new Runnable() {
                          @Override
                          public void run() {
                              for (int i = 0; i <= 5; i++) {
                                  if (0 / 5 == i) {
                                      System.out.println(Thread.currentThread().getName() + "   开始执行 yield ");
                                      Thread.yield();
                                      System.out.println("trhead2");
                                  }
                              }
                          }
                      }, "thread2");
                      Thread thread3 = new Thread(new Runnable() {
                          @Override
                          public void run() {
                              for (int i = 0; i <= 5; i++) {
                                  if (0 / 5 == i) {
                                      System.out.println(Thread.currentThread().getName() + "   开始执行 yield ");
                                      Thread.yield();
                                      System.out.println("trhead3");
                                  }
                              }
      
                          }
                      }, "thread3");
      
                      // 执行三个线程, 正常当运行到yield 是 就会让出cpu执行权,线程到 就绪状态,线程调度器会从 线程就绪队列里获取一个线程优先级最高的线程来执行,
                      // 当然也有可能直接会去到刚刚让出cpu的线程,继续执行yield 后续的代码
                      thread1.start();
                      thread3.start();
                      thread2.start();
      
                  }
              }
      
      执行结果:
      
      thread1   开始执行 yield
      thread2   开始执行 yield
      thread3   开始执行 yield
              trhead2
      trhead1
      trhead3
      
    • interrupt 和 stop

      解释

      interrupt和stop都代表中断线程,区别是 interrupt 会释放资源而stop不会,interrupt也不会立马就中断;说道interrupt就得说一下isInterrupted方法,他是判断线程中断标志的,如果线程A执行了线程B的interrupt方法,线程B在自己的线程中也可以使用 isInterrupted 方法判断自己的中断标志。
       
      注意:在使用 interrupt方法时,如果线程在sleep wait wait(time)状态, 抛出InterruptedException异常后会清除 isInterrupted 方法获取的中断标志位,反之则不会

      代码
      /**
       * @Auther: lantao
       * @Date: 2019-04-17 17:18
       * @Company:
       * @maill:
       * @Description: 在使用 interrupt方法是,如果线程咋sleep wait wait(time) 在抛出InterruptedException异常后会 清除 isInterrupted 方法获取的标志位 其他则不会
       */
              public class InterruptTest {
                  public static void main(String[] args) throws InterruptedException {
                      Thread thread1 = new Thread(() -> {
                          while (true) {}
                      }, "循环线程");
      
                      Thread thread2 = new Thread(() -> {
                          while (true) {
                              try {
                                  Thread.sleep(200);
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                      }, "睡眠线程");
      
                      Thread thread3 = new Thread(() -> {
                          Object o = new Object();
                          while (true) {
                              synchronized (o){
                                  try {
                                      o.wait();
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                              }
                          }
                      }, "等待线程");
      
                      thread1.start();
                      thread2.start();
                      thread3.start();
                      Thread.sleep(500);
      
                      thread1.interrupt();
                      thread2.interrupt();
                      thread3.interrupt();
                      Thread.sleep(500);
                      System.out.println("循环线程isInteryupt is " + thread1.isInterrupted());
                      System.out.println("睡眠线程isInteryupt is " + thread2.isInterrupted());
                      System.out.println("等待线程isInteryupt is " + thread3.isInterrupted());
      
      
                  }
              }
      
      执行结果:
      
      java.lang.InterruptedException: sleep interrupted
      at java.lang.Thread.sleep(Native Method)
      at com.com.concurrenncy.InterruptTest.lambda$main$1(InterruptTest.java:20)
      at java.lang.Thread.run(Thread.java:748)
      java.lang.InterruptedException
      at java.lang.Object.wait(Native Method)
      at java.lang.Object.wait(Object.java:502)
      at com.com.concurrenncy.InterruptTest.lambda$main$2(InterruptTest.java:32)
      at java.lang.Thread.run(Thread.java:748)
      循环线程isInteryupt is true
      睡眠线程isInteryupt is false
      等待线程isInteryupt is false
      

    博客地址:https://lantaoblog.site

    image.png

    相关文章

      网友评论

        本文标题:Java线程生命周期和锁的简单使用

        本文链接:https://www.haomeiwen.com/subject/ldlnjctx.html