JavaEE & wait and notify & 线程状态总结

哎呀,被我抓到了吧!

那你就别走了~

JavaEE & wait and notify & 线程状态总结_第1张图片

文章目录

  • JavaEE & wait and notify & 线程状态总结
    • 1. wait and notify
      • 1.1 应用场景
      • 1.2 wait与notify配合解决问题
        • 1.2.1 wait和notify的使用
        • 1.2.2 wait和notify代码规范
        • 1.2.3 补充
    • 2. 线程状态总结
      • 2.1 NEW
      • 2.2 RUNNABLE
      • 2.3 TERMINATED
      • 2.4 TIMED_WAITING
      • 2.5 BLOCKED
      • 2.6 WAITING

JavaEE & wait and notify & 线程状态总结

1. wait and notify

  • 学到现在,我们已经了解到了阻塞的很多状况
    • 阻塞的本质就是,纠正线程无序调度,让线程在某些需求场景下,有序进行
      • join,等待整个线程结束/等待一段时间
      • sleep,线程固定睡眠
      • synchronized,等待锁
    • 上面的三种,各有各的好,功效有限
  • 而wait呢,它也有它的特性
    • 它引起的阻塞等待,就相当于给线程按了暂停键
  • 而notify呢,则是让线程继续执行
    • 而这个notify应该是阻塞线程外的一个线程调用的
    • 什么时机按下启动键,看具体需要~
  • 而这两个方法进行配合,可以更精细的控制线程调度顺序~

根据 【适用场景:::我们的初心】 去选择阻塞方式~

1.1 应用场景

  • 假设你今天要去银行取钱,ATM没钱了
    • 而其他人都有钱
  • 假设那么ATM是个锁对象
  • 那么你跟其他人一起抢这个锁去操作
  • 而你是要取钱的,如果没人存钱或者没有工作人员运钞填入钱,你就不能取到钱
    • 尽管你抢到锁也没用~
  • 那么,如果你在一个很短的时间内,反复抢到锁,那么是不是就是在浪费时间
    • 这个时间很短,线程的记账信息还没起作用~
  • 而接下来,我们就是为了解决这个问题~

JavaEE & wait and notify & 线程状态总结_第2张图片

1.2 wait与notify配合解决问题

  • 基本思想就是
    • 你抢到ATM机了,你取不到钱,你就wait,直到别人来notify你说,你可以去取钱了~

1.2.1 wait和notify的使用

  • wait和notify都是Object类的方法,只要不是基本数据类型的变量,都可以调用~
  • 谁调用wait,则对应该线程就会阻塞等待
  • 谁调用notify,无所谓,随机唤醒一个WAITING的线程

JavaEE & wait and notify & 线程状态总结_第3张图片

  • 简简单单的调用是会报错的~

JavaEE & wait and notify & 线程状态总结_第4张图片

  • 这里也体现了wait的主要要做的三件事:
    1. 释放锁
    2. 阻塞等待
    3. 等待通知唤醒,唤醒后继续参与“抢锁”
  • 补充: notify能够唤醒的线程,必须和notify的锁对象是一样的
  • notify要依据这个锁去唤醒线程~
    • 没有抢到锁,就notify一样会报错
    • 并且notify也有一步操作是,释放锁,否则被唤醒的线程和其他线程无法去抢夺锁

JavaEE & wait and notify & 线程状态总结_第5张图片

1.2.2 wait和notify代码规范

  • 必须先wait再notify才有效果,否则就没有效果
    • 将相当于你取得到钱,你也没wait阻塞等待,就有人来notify你说,可以取钱去了,你会觉得莫名其妙,但是对你没有什么影响
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        Thread thread1 = new Thread(() -> {
            while(true) {
                System.out.println("wait 前");
                synchronized (object) {
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("wait 后");
            }

        });
        Thread thread2 = new Thread(() -> {
            System.out.println("notify 开始");
            synchronized (object) {
                object.notify();
            }
            System.out.println("notify 结束");
        });
        thread1.start();
        thread2.start();
    }
}
  • 测试结果:

JavaEE & wait and notify & 线程状态总结_第6张图片

  • 顺序正常~
  • 这就是通过具体情况,调整cpu调度顺序的方式~

很多方法都能引起这种效果,但是初心不同,所以,要看具体想法,使用特定的方式~

1.2.3 补充

  1. wait还有一个重载方法,提供了带参数的方法
    • 这个参数代表了,最长等待时间,超过该时间,就自动唤醒~

JavaEE & wait and notify & 线程状态总结_第7张图片

  1. notify还有一个哥哥,notifyAll
    • 他可以根据自己的锁对象,去唤醒所有对应的线程~
    • 而notify是随机唤醒多个中的一个~

在这里插入图片描述

  1. sleep,join好像也能被中断唤醒,也有时间限制,这样就跟wait差不多了咯~

    • 没错,这个场景差不多,但是他们的初心不一样
    • 在不同场景用更加有针对性的方式,才是好决策~
  2. 目前的场景只是为了体现wait和notify的使用方式

    • 你可能没能体会到,他们的配合的在这里对任务的针对性~

      • 并且,锁代码块也并不是只有那么个语句~
        • 以后写的应该是特定情况下会wait~
    • 没有关系,后面我会写几篇博客,研究 Java多线程的一些案例

      • 综合线程知识去研究
      • 结合具体场景运用不同方式

2. 线程状态总结

JavaEE & wait and notify & 线程状态总结_第8张图片

  • 在之前的《进程与线程》博客里给出这张图,由于部分知识未学习,现在重新看一遍~
  • 接下来,我将讲解各个状态,并且用代码去测试

2.1 NEW

NEW 线程还没被创建出来,只是存在这个线程对象~

  • start 创建 + 启动
  • 也就是说start之前~
public class TestState {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            System.out.println("好耶 ^ V ^");
        });
        System.out.println(thread1.getState());
        thread1.start();
    }
}

JavaEE & wait and notify & 线程状态总结_第9张图片

2.2 RUNNABLE

RUNNABLE 运行/就绪状态

  1. 正在CPU上运行准备好
  2. 随时可以去CPU运行
  • 这两种情况,基本“同时”
  • 因为线程并发执行的原因
    • 所以一个线程总是处于运行就绪的状态~
    • 但是这一个很小的时间内,并不是阻塞~
public class TestState {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            System.out.println("好耶 ^ V ^");
        });
        thread1.start();
        System.out.println(thread1.getState());
    }
}

JavaEE & wait and notify & 线程状态总结_第10张图片

2.3 TERMINATED

TERMINATED 系统中的线程已经执行完毕~

  • 但是线程引用还在~
  • 通过这个“还在的”引用去查看状态

由于线程调度的随机性,所以2.2代码是可能出现TERMINATED状态的,如下图:

  • 但是概率低~

JavaEE & wait and notify & 线程状态总结_第11张图片

所以我让main线程等一会儿~

public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("好耶 ^ V ^");
        });
        thread1.start();
        Thread.sleep(10);
        System.out.println(thread1.getState());
    }
}

JavaEE & wait and notify & 线程状态总结_第12张图片

2.4 TIMED_WAITING

TIMED_WAITING

  • 被指定时间的等待—sleep
  • 对于join方法
    • 即使正在等待的线程是完全阻塞的状态
    • 我们可以通过全局性质的静态变量去获得线程引用并在lambda表达式中被捕获到~
    • 如果有时间限制就是TIMED_WAITING~
      • 否则是WAITING~
public class TestState {
    public static Thread t;
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("好耶 ^ V ^");
            System.out.println(t.getState());
        });
        thread1.start();
        t = Thread.currentThread();
        thread1.join(1000);
    }
}

JavaEE & wait and notify & 线程状态总结_第13张图片

public class TestState {
    public static Thread t;
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("好耶 ^ V ^");
            System.out.println(t.getState());
        });
        thread1.start();
        t = Thread.currentThread();
        Thread.sleep(1000);
    }
}

JavaEE & wait and notify & 线程状态总结_第14张图片

public class TestState {
    public static Thread t;
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("好耶 ^ V ^");
            System.out.println(t.getState());
        });
        thread1.start();
        t = Thread.currentThread();
        thread1.join();
    }
}

JavaEE & wait and notify & 线程状态总结_第15张图片

2.5 BLOCKED

BLOCKED

  • 表示等待锁出现的状态
class Counter {
    private int count = 0;
    public void add() {
        synchronized (Counter.class) {
            count++;
        }
    }
    public int get() {
        return count;
    }
}


public class TestState {
    public static Thread t;
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (counter) {
                    counter.add();
                    System.out.println(t.getState());
                }

            }
        });
        thread1.start();
        t = Thread.currentThread();
        for (int i = 0; i < 5000; i++) {
            synchronized (counter) {
                counter.add();
            }
        }
    }
}

JavaEE & wait and notify & 线程状态总结_第16张图片

  • 而main线程可能很快就会执行完,所以就没必要阻塞等待了~

JavaEE & wait and notify & 线程状态总结_第17张图片

2.6 WAITING

  • 主要是因为wait方法
    • join()不带参数版本,是等待整个线程结束
      • 很直接
  • 下面在线程2notify前后分别去查看线程1的状态~
public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        Thread thread1 = new Thread(() -> {
            while(true) {
                System.out.println("wait 前");
                synchronized (object) {
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("wait 后");
            }

        });
        Thread thread2 = new Thread(() -> {
            System.out.println("notify 开始");
            System.out.println(thread1.getState());
            synchronized (object) {
                System.out.println(thread1.getState());
                object.notify();
            }
            System.out.println("notify 结束");
            System.out.println(thread1.getState());
        });
        thread1.start();
        thread2.start();
    }
}

JavaEE & wait and notify & 线程状态总结_第18张图片


文章到此结束!谢谢观看 !
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭

后续会有几篇关联博客,单例模式,阻塞队列,工厂模式,计时器,线程池等等…

敬请期待吧~


你可能感兴趣的:(JavaEE,java-ee,java,jvm)