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

做网站有骗子理发美发培训学校

做网站有骗子,理发美发培训学校,iis如何添加网站,陕西省住建厅官网在大家的认知里,或者大家也可能搜过,notify唤醒机制到底是随机的呢?还是顺序的呢?在网上其实也有很多人说notify的唤醒机制就是随机的,但实际上并不是这样的,notify的唤醒机制是先进先出的! 目…

          在大家的认知里,或者大家也可能搜过,notify唤醒机制到底是随机的呢?还是顺序的呢?在网上其实也有很多人说notify的唤醒机制就是随机的,但实际上并不是这样的,notify的唤醒机制是先进先出的!

目录

源码注释说明

具体测试用例

测试用例一

测试用例二

底层原理解析

ObjectMonitor 的数据结构

wait源码

notify源码

 DequeueWaiter源码

  源码结论     


源码注释说明

让我们先来看看源码注释是怎么写的

Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

翻译为:

唤醒正在等待此对象的监视器的单个线程。如果任何线程正在等待此对象,则选择其中一个线程进行唤醒。选择是任意的,由实现自行决定。线程通过调用其中一个 wait 方法等待对象的监视器。

      在注释中其实就已经说明了,选择是任意的,由实现自行决定的,既然注释都这样写了,那我们就先用测试用例测试一下。

具体测试用例

测试用例一

public class Main {private static final Object lock = new Object();private static List<String> awakingOrder = Collections.synchronizedList(new ArrayList<>());private static final int THREAD_COUNT = 100;private static CountDownLatch readyLatch = new CountDownLatch(THREAD_COUNT);private static CountDownLatch startLatch = new CountDownLatch(1);private static CountDownLatch finishLatch = new CountDownLatch(THREAD_COUNT);static class WaitingThread extends Thread {private String name;public WaitingThread(String name) {this.name = name;}@Overridepublic void run() {try {// 先通知主线程该线程已准备就绪readyLatch.countDown();// 等待主线程发出开始信号startLatch.await();synchronized (lock) {System.out.println(name + " 准备等待");lock.wait();awakingOrder.add(name);System.out.println(name + " 被唤醒");}} catch (InterruptedException e) {e.printStackTrace();} finally {finishLatch.countDown();}}}public static void main(String[] args) throws InterruptedException {List<WaitingThread> threads = new ArrayList<>();// 创建并启动100个线程for (int i = 1; i <= THREAD_COUNT; i++) {WaitingThread thread = new WaitingThread("线程" + i);threads.add(thread);thread.start();}// 等待所有线程准备就绪readyLatch.await();System.out.println("所有线程已准备就绪");// 发出开始信号,让所有线程开始等待startLatch.countDown();// 确保所有线程都进入等待状态Thread.sleep(1000);// 依次唤醒所有线程for (int i = 0; i < THREAD_COUNT; i++) {synchronized (lock) {System.out.println("开始第 " + (i + 1) + " 次唤醒");lock.notify();}// 给一点时间让被唤醒的线程执行完毕Thread.sleep(10);}// 等待所有线程执行完毕finishLatch.await();// 输出唤醒顺序System.out.println("唤醒顺序: " + awakingOrder);System.out.println("唤醒的线程总数: " + awakingOrder.size());}
}

       测试用例代码如上,我一开始看的时候还在想HotSpot JVM的的notify唤醒机制原来真的是顺序唤醒的,但是我再仔细看的时候发现并不是这样的!

        当我再往上看的时候发现,原来因为线程并发执行的原因导致并不是按照我原先设置的顺序获取到了synchronized锁!而导致了这个原因,经过对比其实可以发现,线程获取到锁等待的顺序是和被唤醒的顺序是一致的!所以HotSpot JVM的notify实现是先进先出的有序队列。

测试用例二

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class Main {private static final Object lock = new Object();private static List<String> awakingOrder = Collections.synchronizedList(new ArrayList<>());private static final int THREAD_COUNT = 100;private static volatile int currentThreadIndex = 0;static class WaitingThread extends Thread {private String name;private int index;private CountDownLatch prevLatch;private CountDownLatch myLatch;public WaitingThread(String name, int index, CountDownLatch prevLatch, CountDownLatch myLatch) {this.name = name;this.index = index;this.prevLatch = prevLatch;this.myLatch = myLatch;}@Overridepublic void run() {try {// 等待前一个线程就绪if (prevLatch != null) {prevLatch.await();}synchronized (lock) {System.out.println(name + " 准备等待,序号: " + index);// 通知下一个线程可以开始等待if (myLatch != null) {myLatch.countDown();}lock.wait();awakingOrder.add(name);System.out.println(name + " 被唤醒,序号: " + index);}} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) throws InterruptedException {List<WaitingThread> threads = new ArrayList<>();List<CountDownLatch> latches = new ArrayList<>();// 创建用于线程间同步的CountDownLatch数组for (int i = 0; i < THREAD_COUNT; i++) {latches.add(new CountDownLatch(1));}// 创建并启动线程for (int i = 0; i < THREAD_COUNT; i++) {CountDownLatch prevLatch = i == 0 ? null : latches.get(i - 1);CountDownLatch myLatch = latches.get(i);WaitingThread thread = new WaitingThread("线程" + (i + 1), i + 1, prevLatch, myLatch);threads.add(thread);thread.start();}// 等待一段时间确保所有线程都进入等待状态Thread.sleep(2000);System.out.println("开始按顺序唤醒线程");// 按顺序唤醒线程for (int i = 0; i < THREAD_COUNT; i++) {synchronized (lock) {System.out.println("准备唤醒第 " + (i + 1) + " 个线程");lock.notify();}// 给足够的时间让被唤醒的线程完成执行Thread.sleep(50);}// 等待所有线程完成for (Thread thread : threads) {thread.join();}// 输出唤醒顺序System.out.println("唤醒顺序: " + awakingOrder);System.out.println("唤醒的线程总数: " + awakingOrder.size());// 验证唤醒顺序是否正确boolean isOrdered = true;for (int i = 0; i < awakingOrder.size(); i++) {String expectedThread = "线程" + (i + 1);if (!awakingOrder.get(i).equals(expectedThread)) {isOrdered = false;break;}}System.out.println("唤醒顺序是否正确: " + isOrdered);}
}

       修改原来的代码 ,为每个线程创建一个 CountDownLatch,每个线程需要等待前一个线程进入等待状态才能继续,使用 prevLatch 和 myLatch 确保线程按顺序进入等待状态,这样就可以顺序的进入锁了,让我们再看下运行结果

 这样其实就可以清晰的看到这个唤醒的结果了,就是先进先出,顺序!

底层原理解析

现在让我们深入分析 HotSpot JVM 中的实现原理

ObjectMonitor 的数据结构

ObjectMonitor 的数据结构在 HotSpot 中,synchronized 的实现依赖于 ObjectMonitor 类,其结构如下:

ObjectMonitor() {_header       = NULL;_count        = 0;_waiters      = 0;_recursions   = 0;_object       = NULL;_owner        = NULL;_WaitSet      = NULL;    // 等待线程队列_WaitSetLock  = 0;_Responsible  = NULL;_succ         = NULL;_cxq          = NULL;FreeNext      = NULL;_EntryList    = NULL;    // 待竞争线程队列_SpinFreq     = 0;_SpinClock    = 0;
}

wait源码

让我们看看具体的wait等待实现

void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {// 将当前线程封装成 ObjectWaiter 对象ObjectWaiter node(THREAD);node.TState = ObjectWaiter::TS_WAIT;// 加入等待队列AddWaiter(&node);// 释放对象锁exit(true, THREAD);// 等待被唤醒Thread::SpinWait(node);
}

notify源码

再看看notify的唤醒实现 

void ObjectMonitor::notify(TRAPS) {// DequeueWaiter 方法会从 _WaitSet 队列头部取出一个等待线程ObjectWaiter* waiter = DequeueWaiter();if (waiter != NULL) {// 将等待线程移动到 EntryListExitExit(waiter);}
}

 DequeueWaiter源码

ObjectWaiter* ObjectMonitor::DequeueWaiter() {// 从 _WaitSet 队列头部获取第一个等待线程ObjectWaiter* waiter = _WaitSet;if (waiter != NULL) {_WaitSet = waiter->_next;waiter->_prev = NULL;waiter->_next = NULL;}return waiter;
}

  源码结论     

         从源码可以看出,wait() 的线程被放入 WaitSet 队列,notify() 总是唤醒 WaitSet 队列中的第一个线程,虽然 Java 规范说 notify 的选择是随机的,但在 HotSpot 实现中实际上是 FIFO(先进先出)的

      运行上面的测试代码,你也会发现,线程被唤醒的顺序与它们进入等待状态的顺序是一致的,多次运行结果都是一样的(在相同的 JVM 实现下),这验证了在 HotSpot JVM 中,notify() 确实是按照 FIFO 顺序唤醒线程的

      但需要注意的是:这个行为是 HotSpot JVM 的具体实现,其他 JVM 可能会有不同的实现

 

http://www.dtcms.com/wzjs/146057.html

相关文章:

  • 关于公司网站建设的若干意见免费关键词优化排名软件
  • 开平网站建设公司关键词排名软件官网
  • 把域名解析到其他网站的ip地址叫太原网站优化公司
  • html网站简易模板海外社交媒体营销
  • 无锡网站App微信网站整站优化
  • 做网站建设公司赚钱今日十大热点新闻
  • 项目网站建设方案池州网络推广
  • 网站问卷调查怎么做手机百度一下百度
  • 网站怎么做 流程图常州百度推广代理
  • 工程做网站百度指数怎么查询
  • 直播类网站怎么做qq群引流推广网站
  • 网站开发定制案例展示旺道seo工具
  • 做网站优化的话术搭建网站教程
  • 成都网站建设公司地址免费b站推广网站不
  • 佛山厂家关键词网络推广深圳网络优化seo
  • 做课件的网站有哪些广告传媒公司
  • 潍坊做网站的公司网站设计公司多少钱
  • 网站开发多语言切换思路百度seo高级优化
  • 网站建设专业的公司哪家好微信软文范例大全100
  • 网站建设功能百度安装
  • 小生意是做网站还是公众号网络软文发布平台
  • 南京网站建设网站营销网站制作公司
  • 电影网站推荐哪个网站好自己有产品怎么网络销售
  • 做外国网站自媒体太原今日新闻最新头条
  • 企业解决方案中的关键点合肥seo优化排名公司
  • 现在asp做网站百度竞价排名正确解释
  • 域名到网站上线沈阳专业seo
  • 自己做网站要会什么软件做网站多少钱一年
  • 五大建设的内容seo云优化软件
  • 白酒 网站模板seo研究中心