【20220608作业①】线程的BLOCKED状态和WAITING状态的区别

BLOCKED状态和WAITING状态

  • BLOCKED状态
    • 一、是什么
    • 二、什么情况下会使线程进入BLOCKED状态
      • 1. 等待监视器锁进入同步块/方法
        • 1)监视器锁
          • 监视器锁是什么?
          • MonitorEnter进入(注2)
          • MonitorExit退出(注2)
        • 2)解读 - 等待监视器锁进入同步块/方法
          • synchroinzed原理分析
        • 3)示例
      • 2. 调用object.wait后重新进入一个同步块/方法
        • 1)示例
  • WAITING状态
    • 一、是什么
    • 二、什么情况下会进入
      • wait/notify/notifyAll
        • 示例
        • 原理
          • Object.wait
          • Object.notify
          • Object.notifyAll
      • Thread.join
        • 示例
        • 原理
      • LockSupport.park
        • 示例
        • 原理
          • unpark(源码见注5)
  • 两个状态之间的区别(总结)
  • 扩展

BLOCKED状态

一、是什么

BLOCKED是线程的一种状态,Thread.state中对其的介绍:

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED

翻译:

等待监视器锁的线程阻塞的线程状态。一个处于阻塞状态的线程正在等待一个监视器锁进入一个同步的块/方法或在调用Object.wait之后重新进入一个同步的块/方法

理解:表示线程当前正在等待获取到锁进入同步块/方法

二、什么情况下会使线程进入BLOCKED状态

解读上述翻译内容,线程有两种情况:①等待监视器锁进入同步块/方法;②调用object.wait后重新进入一个同步块/方法。

1. 等待监视器锁进入同步块/方法

1)监视器锁
监视器锁是什么?

任何一个对象都有一个Monitor与之关联,当且一个Monitor被持有后,它将处于锁定状态。Synchronized在JVM里的实现都是
基于进入和退出Monitor对象来实现方法同步和代码块同步,虽然具体实现细节不一样,但是都可以通过成对的MonitorEnter和
MonitorExit指令来实现。(注1)
【20220608作业①】线程的BLOCKED状态和WAITING状态的区别_第1张图片

MonitorEnter进入(注2)

每个对象都是一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

  1. 如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者;
  2. 如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1;
  3. 如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权;
    思考:为什么允许重新进入?
MonitorExit退出(注2)

执行monitorexit的线程必须是对象引用所对应的monitor的所有者。指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。 其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。

2)解读 - 等待监视器锁进入同步块/方法

等待监视器锁进入同步块/方法,也就是使用synchroinzed关键字标注某个类或者某个方法,标注的代码部分就是同步块/方法,** 等待进入该方法的线程的状态就是BLOCKED阻塞状态 **。

synchroinzed原理分析

synchroinzed本质是给当前类或指定某个对象加锁。结合监视器锁的概念总结,synchroinzed是在编译时** 对这个类添加ACC_SYNCHRONIZED标志 ** 或者 ** 在方法代码内容前后添加monitorenter 和 monitorexit 指令 **,利用Monitor监视器锁实现方法与代码块同步。(注3)

对象加锁的情况:

 private static Object object = new Object();
 
    public static void testSync(){
   
        synchronized(object) {
   
            System.out.println("当前占用线程: " + Thread.currentThread().getName());
            try {
   
                Thread.sleep(100000000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
    }

对象加锁字节码打印:
【20220608作业①】线程的BLOCKED状态和WAITING状态的区别_第2张图片
思考:为什么会有两个monitorexit?

类加锁的情况:

 public static synchronized void testSync(){
   
        System.out.println("当前占用线程: " + Thread.currentThread().getName());
        try {
   
            Thread.sleep(100000000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
    }

类加锁字节码打印:
【20220608作业①】线程的BLOCKED状态和WAITING状态的区别_第3张图片

3)示例

以类锁情况为例:

package com.example.demo.thread;

/**
 * @author: dongzhengbei
 * @since: 2022.06.28 10:15
 */
public class BlockAndWait {
   

    public static synchronized void testSync(){
   
        System.out.println("当前占用线程: " + Thread.currentThread().getName());
        try {
   
            Thread.sleep(100000000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
   
        Thread a = new Thread((<

你可能感兴趣的:(Java,并发,java,后端)