当前位置: 首页 > news >正文

建设部网站如何下载规范 标准上海好的seo公司

建设部网站如何下载规范 标准,上海好的seo公司,wordpress 空间商,wordpress添加特效目录 〇、先总结一下这三个方法带来的Java线程状态变化 一、obj.wait() 1.1 作用 1.2 使用前需要持有线程共享对象的锁 1.3 使用技巧 二、obj.notify(All)() 1.1 notify() 方法 1.1.1 调用notify()或notifyAll()不会释放线程的锁 1.2 notifyAll() 方法 1.3 使用技巧 三、使用实…

目录

〇、先总结一下这三个方法带来的Java线程状态变化

一、obj.wait()

1.1 作用

1.2 使用前需要持有线程共享对象的锁

1.3 使用技巧

二、obj.notify(All)()

1.1 notify() 方法

1.1.1 调用notify()或notifyAll()不会释放线程的锁

1.2 notifyAll() 方法

1.3 使用技巧

三、使用实例

四、wait()/notify()/notifyAll() 为什么定义在 Object 类中?


wait()、notify/notifyAll() 方法都是Object的本地final方法,无法被重写。

〇、先总结一下这三个方法带来的Java线程状态变化

当Java线程调用wait()方法后,该线程会进入等待队列,并且会释放占用的锁资源。线程状态会变为WAITING或TIMED_WAITING。该线程不会被挂起到外存,而是在内存中等待被唤醒。线程等待的条件通常是由其他线程调用notify()或notifyAll()方法来唤醒该线程。

当线程被唤醒时,它会重新尝试获取锁资源并从wait()方法返回。线程状态会变为BLOCKED,直到它获得了锁资源为止。如果成功获取锁资源,线程状态会变为RUNNABLE,然后可以继续执行。如果获取锁资源失败,则线程会继续等待,并且状态会维持在BLOCKED或WAITING或TIMED_WAITING状态,直到它再次被唤醒。

需要注意的是,线程在等待期间会消耗一定的资源,因此应该避免过多的线程等待。另外,线程在等待期间不会占用CPU时间片,因此可以减少CPU的利用率,提高系统的性能。

一、obj.wait()

1.1 作用

wait()是Object里面的方法,Object是所有对象的父类,即所有对象都可以调用wait()方法。wait方法还有可以传入等待时长的,可以让线程等待指定的时间后自动被唤醒。调用wait()会使Java线程进入到WAITING状态,调用wait(long time)会使Java线程进入到TIMED_WAITING状态(WAITING和TIMED_WAITING状态就是阻塞状态)

当一个线程调用一个共享变量的wait()方法时,该线程会阻塞(等待)。直到发生以下几种情况才会恢复执行:

  • 其他线程调用了该共享对象的 notify() 方法或者 notifyAll() 方法(继续往下走)
  • 其他线程调用了该线程的 interrupt() 方法,该线程会 InterruptedException 异常返回

等待线程:假设调用的是obj对象的wait()方法,wait的执行线程,也就是被暂停的线程,就称为对象obj上的等待线程。对象的wait方法可能被不同的线程执行,所以同一个对象可能会有多个等待线程。

1.2 使用前需要持有线程共享对象的锁

在使用wait()、notify()和notifyAll()方法方法前,需要先持有锁。如果调用线程共享对象的wait()、notify()和notifyAll()方法的线程没有事先获取该对象的监视器锁,调用线程会抛出IllegalMonitorStateException 异常。当线程调用wait() 之后,就会释放该对象的监视器锁

使用wait()notify()notifyAll()方法方法前,需要先持有锁:

  • 表象:wait、notify(ALL)方法需要调用 monitor 对象
  • 本质:Java的线程通信实质上是共享内存,而不是直接通信

那么,一个线程如何才能获取一个共享变量的监视器锁?

1、执行synchronized 同步代码块,使用该共享变量作为参数。

synchronized(共享变量) {// TODO
}

2、调用该共享变量的同步方法(synchronized 修饰)

synchronized void sum(int a, int b) {// TODO
}

 如下代码示例,线程A与线程B,在线程A中调用共享变量obj的wait()方法,在线程B中进行唤醒notify()。

/*** Object的Wati()方法的使用*/
@Slf4j
public class WaitTest {public static void main(String[] args) {// 定义一个共享变量Object obj = new Object();// 创建线程AThread threadA = new Thread(new Runnable() {@Overridepublic void run() {log.info("线程" + Thread.currentThread().getName()+"开始执行");try {// 获取共享变量的对象锁synchronized(obj){// 线程A 等待log.info("线程" + Thread.currentThread().getName()+"等待");// 调用wait(),线程A阻塞,并且释放掉获取到的obj的对象锁obj.wait();}} catch (InterruptedException e) {e.printStackTrace();}log.info("线程" + Thread.currentThread().getName()+"执行结束");}},"A");// 创建线程BThread threadB = new Thread(new Runnable() {@Overridepublic void run() {log.info("线程" + Thread.currentThread().getName()+"开始执行");// 获取共享变量锁synchronized (obj){//  线程B 唤醒或者中断  调用obj的唤醒操作或者使A线程中断的操作都可以将正在阻塞的A线程唤醒log.info("线程" + Thread.currentThread().getName()+"唤醒");obj.notify(); // 唤醒操作// threadA.interrupted(); // 中断操作}log.info("线程" + Thread.currentThread().getName()+"执行结束");}},"B");// 启动线程AthreadA.start();try {// 等待200ms,让线程B获取资源,在这200ms期间A就被阻塞了,释放了obj对象锁Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}// 启动线程BthreadB.start();}
}

执行结果:

线程A开始执行

线程B开始执行

线程B执行结束

线程A执行结束

可以看到主程序线程A启动之后,休眠了200ms让出cup执行权,线程B开始执行后调用notify()方法对阻塞线程A进行唤醒。

故:当一个线程调用一个共享变量的wait()方法时,该调用线程会被阻塞挂起,直到发生下面几件事情之一才返回:(1)其他线程调用了该共享对象的notify()或者notifyAll()方法;(2)其他线程调用了该线程的interrupt()方法,该线程抛出InterruptedException异常返回。

1.3 使用技巧

  • wait()方法一般配合while使用
    • 被唤醒后会重新竞争锁,之后从上次wait位置重新运行
    • while 多次判断,防止在wait这段时间内对象被修改

二、obj.notify(All)()

notify()和notifyAll()方法也是Object里面的方法,Object是所有对象的父类,即所有对象都可以调用notify()和notifyAll()方法。但是线程中共享变量在调用这两个方法前,该线程需要获取到这个共享变量的锁才可以,否则会抛出异常。

1.1 notify() 方法

一个线程调用共享对象的 notify() 方法后,会唤醒一个在该共享变量上调用 wait(...) 系列方法后阻塞的线程。

通知线程:调用notify/notifyAll方法时所在的线程叫做通知线程。

1.1.1 调用notify()notifyAll()不会释放线程的锁

当线程调用notify()或notifyAll()方法时,它不会释放掉线程持有的锁。

在Java中,每个对象都有一个相关联的锁,也称为监视器锁。当一个线程需要访问被该锁保护的对象时,它必须先获得该锁的所有权。所以只有获得锁的线程才能调用wait()、notify()和notifyAll()方法。

当线程调用notify()或notifyAll()方法时,它仅仅是唤醒等待在该对象上的一个或多个线程,以便它们可以继续执行。它不会释放线程持有的锁。因此,其他线程仍然无法访问被该锁保护的对象,直到调用notify()或notifyAll()方法的线程释放锁资源。

在多线程编程中,必须小心地管理锁,以避免死锁和竞争条件等问题。通常,为了确保线程安全和避免死锁,必须确保在访问共享资源时只有一个线程持有锁。当然,这也需要合理地使用wait()、notify()和notifyAll()方法来协调线程的执行顺序。

值得注意的是:

  • 一个共享变量上可能会有多个线程在等待,notify()具体唤醒哪个等待的线程是随机的
  • 被唤醒的线程不能马上从wait()方法返回并继续执行,它必须在获取了共享对象的监视器锁后才可以返回,等到唤醒它的线程释放了共享变量上的监视器锁后,被唤醒的线程也不一定会获取到共享对象的监视器锁,这是因为该线程还需要和其他线程一起竞争该锁,只有该线程竞争到了共享变量的监视器锁后才可以继续执行

1.2 notifyAll() 方法

notifyAll() 方法则会唤醒所有在该共享变量上由于调用wait系列方法而被挂起的线程。

1.3 使用技巧

尽量让notify / notifyAll()靠近临界区结束的地方。免得等待线程因为没有获得对象的锁,而又进入等待状态。

三、使用实例

比较经典的就是生产者和消费者的例子。

在生产者消费者模型中,推荐使用notifyAll,因为notify唤醒的线程不确定是生产者或消费者。

public class NotifyWaitDemo {// 共享变量队列的最大容量public static final int MAX_SIZE = 1024;// 共享变量public static Queue queue = new Queue();public static void main(String[] args) {// 生产者Thread producer = new Thread(() -> {// 获取共享变量的锁才能调用wait()方法synchronized (queue) {// 一般wait()都配合着while使用,因为线程唤醒后需要不断地轮循来尝试获取锁while (true) {// 当队列满了之后就挂起当前线程(生产者线程)// 并且,释放通过queue的监视器锁,让消费者对象获取到锁,执行消费逻辑if (queue.size() == MAX_SIZE) {try {// 阻塞生产者线程,并且使当前线程释放掉共享变量的锁queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 空闲则生成元素,并且通知消费线程queue.add();// 唤醒消费者来消费,建议用notifyAll(),因为notify()无法确定会唤醒哪一个线程queue.notifyAll();}}});// 消费者Thread consumer = new Thread(() -> {// 需要先获取锁synchronized (queue) {while (true) {// 当队列已经空了之后就挂起当前线程(消费者线程)// 并且,释放通过queue的监视器锁,让生产者对象获取到锁,执行生产逻辑if (queue.size() == 0) {try {// 阻塞消费者线程,并释放共享对象的锁queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 空闲则消费元素,并且通知生产线程queue.take();queue.notifyAll();}}});// 先执行生产者线程producer.start();try {// 将当前线程睡眠1000ms,让生产者先将队列生产满,然后wait阻塞起来,并且释放持有的锁。为了后续能执行消费者线程Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 执行消费者线程consumer.start();}// 共享变量static class Queue {private int size = 0;public int size() {return this.size;}// 生产操作public void add() {// TODOsize++;System.out.println("执行add 操作,current size: " +  size);}// 消费操作public void take() {// TODOsize--;System.out.println("执行take 操作,current size: " +  size);}}
}

 

四、wait()/notify()/notifyAll() 为什么定义在 Object 类中?

由于Thread类继承了Object类,所以Thread也可以调用者三个方法,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法是定义在Object类中。


 相关文章:【并发基础】一篇文章带你彻底搞懂睡眠、阻塞、挂起、终止之间的区别
                  【并发基础】Java中线程的创建和运行以及相关源码分析           
                  【并发基础】线程,进程,协程的详细解释
                 【并发基础】操作系统中线程/进程的生命周期与状态流转以及Java线程的状态流转详解

http://www.tj-hxxt.cn/news/66042.html

相关文章:

  • 甘肃省建设银行网站手机网页链接制作
  • 淄博桓台网站建设方案google框架一键安装
  • 齐博企业网站朝阳seo搜索引擎
  • 公司网站推广方案济南计算机培训机构哪个最好
  • 少女前线b站服免费网络推广平台有哪些
  • b2c 外贸网站建设百度权重3的网站值多少
  • 网站建设及运营 多少钱今日油价92汽油价格调整最新消息
  • 胶州做网站公司营业推广促销
  • 在线做数据图的网站有哪些问题百度网盘资源搜索引擎入口
  • 一级域名网站如何申请免费个人自助建站
  • h5模板下载有哪些网站国外新闻最新消息
  • 网站建设的原则 流程专业网站优化排名
  • 极路由 做网站seo标题优化的心得总结
  • 网站链接怎么做参考文献网络推广费用
  • 印章在线制作网站徐州seo排名收费
  • 全球咨询公司最新排名网站排名优化培训课程
  • 模板网站建设的弊端宁波seo教学
  • 做网站实例互联网营销师证书骗局
  • 做批发的网站有哪些注册安全工程师
  • 佛山做外贸网站特色站长工具seo综合查询可以访问
  • 新安人才网系统优化软件
  • 医疗企业网站模板网络营销方案的范文
  • 苏州做网站推广的公司哪家好竞价广告
  • 高明网站设计企业网络营销成功案例
  • 政府网站建设资质怎样制作一个自己的网站
  • 最受欢迎的wordpress主题seo网站关键词排名软件
  • 网站模板怎样在本地测试seo资源咨询
  • 烟台网站建设4038gzs汕头百度网站推广
  • 只做乡村旅游的网站游戏推广平台
  • 什么网站可以直接做word文档比较靠谱的推广公司