首页 文章 精选 留言 我的

精选列表

搜索[面试],共4915篇文章
优秀的个人博客,低调大师

史上最难的一道Java面试题:分析篇

无意中了解到如下题目,觉得蛮好。 题目如下: 该程序的输出结果? 程序输出结果 考察知识点 synchronize实例锁。 并发下的内存可见性。 在java中,多线程的程序最难理解、调试,很多时候执行结果并不像我们想象的那样执行。所以在java多线程特别难,依稀记得大学的时候考c语言二级的时候,里面的题目是什么++和很多其他优先级的符合在一起问最后的输出结果,这类题目就想考一些运行符优先级和结合性问题。那个背背就行了,但是java多线程还是需要好好理解才行,靠背是不行的。 下面开始简单分析: 该题目涉及到2个线程(主线程main、子线程)、关键词涉及到synchronized、Thread.sleep。 synchronized关键词还是比较复杂的(可能有时候没有理解到位所以上面题目会有点误区),他的作用就是实现线程的同步(实现线程同步有很多方法,它只是一种后续文章会说其他的,需要好好研究大神Doug Lea的一些实现),它的工作就是对需要同步的代码加锁,使得每一次只有一个线程可以进入同步块(其实是一种悲观策略)从而保证线程只记得安全性。 一般关键词synchronized的用法 指定加锁对象:对给定对象加锁,进入同步代码前需要活的给定对象的锁。 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。 上面的代码,synchronized用法其实就 属于第二种情况。直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。 可能存在的误区 由于对synchronized理解的不到为,由于很多时候,我们多线程都是操作一个synchronized的方法,当2个线程调用2个不同synchronized的方法的时候,认为是没有关系的,这种想法是存在误区的。直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。 如果一个调用synchronized方法。另外一个调用普通方法是没有关系的,2个是不存在等待关系的。 这些对于后面的分析很有作用。 Thread.sleep 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常,对于后面的分析很有作用。 分析流程 java 都是从main方法执行的,上面说了有2个线程,但是这里就算修改线程优先级也没用,优先级是在2个程序都还没有执行的时候才有先后,现在这个代码一执行,主线程main已经执行了。 对于属性变量 int b =100由于使用了synchronized也不会存在可见性问题(也没有必要在说使用volatile申明)。 当执行1步骤的时候(Thread t = new Thread(tt); //1)线程是new状态,还没有开始工作。 当执行2步骤的时候(t.start(); //2)当调用start方法,这个线程才正真被启动,进入runnable状态,runnable状态表示可以执行,一切准备就绪了,但是并不表示一定在cpu上面执行,有没有真正执行取决服务cpu的调度。 在这里当执行3步骤必定是先获得锁(由于start需要调用native方法,并且在用完成之后在一切准备就绪了,但是并不表示一定在cpu上面执行,有没有真正执行取决服务cpu的调度,之后才会调用run方法,执行m1方法)。 这里其实2个synchronized方法里面的Thread.sheep其实要不要是无所谓的,估计是就为混淆增加难度。3步骤执行的时候其实很快子线程也准备好了,但是由于synchronized的存在,并且是作用同一对象,所以子线程就只有必须等待了。由于main方法里面执行顺序是顺序执行的,所以必须是步骤3执行完成之后才可以到4步骤,而由于3步骤执行完成,子线程就可以执行m1了。 这里就存在一个多线程谁先获取到问题,如果4步骤先获取那么main thread b=2000,如果子线程m1获取到可能就b已经赋值成1000或者还没有来得及赋值4步骤就输出了可能结果就是main thread b=1000或者main thread b=2000,在这里如果把6步骤去掉那么b=执行在前和main thread b=在前就不确定了。但是由于6步骤存在,所以不管怎么都是main thread b=在前面,那么等于1000还是2000看情况,之后b=1000是一定固定的了。 多线程一些建议 线程也很珍贵,所以建议使用线程池,线程池用的很多,后续准备分享下,特别总要,需要做到心中有数。 给线程起名字,当线上cpu高的时候,需要用到高级jstack,如果有名称就方便很多。 多线程特别需要注意线程安全问题,也需要了解jdk那些是线程安全不安全,那样使用的时候不会出现莫名其妙问题。 还有一些技巧后续文章分享在慢慢提,多线程特别重要,也特别难,希望大家也多多花心思在上面。 多线程的一些调试技巧 由于断点,所有线程经过断点的时候,都需要停下,导致这个点不停的断住,很难受,eclispe里面有条件断点,当满足条件的时候就可以停下来,那么这样就方便了。 欢迎工作一到五年的Java工程师朋友们加入Java架构开发:860113481 群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

优秀的个人博客,低调大师

九道前端面试题及答案,妹子总结的

1、什么是W3C标准? WEB标准不是某一个标准,而是一系列标准的集合。网页主要由三部分组成:结构(Structure)、表现(Presentation)和行为(Behavior)。对应的标准也分三方面:结构化标准语言主要包括XHTML和XML,表现标准语言主要包括CSS,行为标准主要包括对象模型(如W3C DOM)、ECMAScript等。 2、bootstrap响应式原理 是通过栅格系统和媒体查询实现的 // 小屏幕(平板,大于等于 768px)@media (min-width: @screen-sm-min) { ... }// 中等屏幕(桌面显示器,大于等于 992px)@media (min-width: @screen-md-min) { ... }// 大屏幕(大桌面显示器,大于等于 1200... 3、HTML/XHTM的区别 XHTML 与 HTML 4.01 标准没有太多的不同。 XHTML 元素必须被正确地嵌套。 XHTML 元素必须被关闭。 标签名必须用小写字母。 XHTML 文档必须拥有根元素。 4、页面构架和布局 布局可以是编码方面的,也可以是视觉方面的。 编码方面的涉及到语义化标签(也包含了div+css)布局、iframe框架(特殊地方使用)布局和表格布局(只用于一些特殊的地方,不推荐全站使用),具体你可以百度下了解学习下相关知识。 如果是视觉交互方面的,就比较多了,每年都会有新的设计布局,高级一点的比如视差类型布局,全屏布局,瀑布流,无缝拼图布局等,这些都不局限于传统的布局方式;传统电子商务、信息类的大多采用单栏、两栏或者三栏布局,还有更多栏布局;分辨率相关的宽屏布局和窄屏布局,感应式布局。太多的选择了,要学习的东西也比较多,要慢慢了解啦。还有更多的布局需要慢慢摸索和体验。我把我知道的说了。 至于手机端,例举一些:竖排列表、横排方块、九宫格、TAB切换式、手风琴布局(有多个分类及其内容同时展示)、抽屉/侧边栏、标签场景式),因为屏幕小,要增加用户体验都可以根据具体情况用不同的布局方式。 5、BootStrap学习笔记,优缺点总结 优点: BT的优势之一就是可以根据用户屏幕尺寸调整页面,使其在各个尺寸上都表现良好。 BT预先定义了很多CSS类,使用的时候直接给class赋予对应的类名即可,如text-left,text-align,.table等。最有代表性的就是btn类,BT定义了一个.bt的基础类,如果还想要其他样式可以在这个基础类上进行扩展,实现不同的视觉效果。 BT的JavaScript插件非常丰富,既可以用现成的也可以自己扩充,BT提供了一个集成板的BT.js您可以直接拿过来使用也可以单个使用引入*.js即可。 不足: 对IE兼容也存在不小的问题,BT将所有的元素盒模型都设置成了border-box,这是IE混杂模式下的盒模型,光这点就导致了不能兼容IE。此外还用到了大量的H5标签以及CSS3语法,这些语法标签兼容性方面同样存在不小的问题,当然网上存在很多兼容IE的办法,但需要引入其他文件,有些还不小,势必导致加载速度变慢,影响用户体验。 BT对IE6,7的兼容性肯定不好,对IE8的支持也需要一些额外的文件。 IE8的媒体查询需要response.js的配合才能实现 BT 不支持 IE 古老的兼容模式。为了让 IE 浏览器运行最新的渲染模式下,建议将此 <meta> 标签加入到你的页面中: <meta http-equiv="X-UA-Compatible" content="IE=edge"> 按 F12 键打开 IE 的调试工具,就可以看到 IE 当前的渲染模式是什么。 BT属于前端UI库,可以快速搭建前端页面,以及设计响应式界面,还可以使用saas重新设计组件, 6、JQeury学习笔记,优缺点总结 优点: jQuery实现脚本与页面的分离,是操作DOM的首选js库。 最少的代码做最多的事情 最少的代码做最多的事情,这是jQuery的口号,而且名副其实。使用它的高级selector,开发者只需编写几行代码就能实现令人惊奇的效果。开发者无需过于担忧浏览器差异,它除了还完全支持Ajax,而且拥有许多提高开发者编程效率的其它抽象概念。jQuery把JavaScript带到了一个更高的层次。以下是一个非常简单的示例: 代码如下: $("p.neat").addClass("ohmy").show("slow"); 通过以上简短的代码,开发者可以遍历“neat”类中所有的<p>元素,然后向其增加“ohmy”类,同时以动画效果缓缓显示每一个段落。开发者无需检查客户端浏览器类型,无需编写循环代码,无需编写复杂的动画函数,仅仅通过一行代码就能实现上述效果。 性能 在大型JavaScript框架中,jQuery对性能的理解最好。尽管不同版本拥有众多新功能,其最精简版本只有18KB大小,这个数字已经很难再减少。jQuery的每一个版本都有重大性能提高。 插件 基于jQuery开发的插件目前已经有大约数千个。开发者可使用插件来进行表单确认、图表种类、字段提示、动画、进度条等任务。 节省开发者学习时间 当然要想真正学习jQuery,开发者还是需要投入一点时间,尤其是如果你要编写大量代码或自主插件的话,更是如此。但是,开发者可以采取“各个击破”的方式,而且jQuery提供了大量示例代码,入门是一件非常容易的事情。 不足: 不能向后兼容 插件兼容性。 jQuery的稳定性 在大型框架中,jQuery核心代码库对动画和特效的支持相对较差。 7、”高内聚 ,低耦合“到底是什么意思? ‘高内聚,低耦合’是相对于代码而言,一个项目中: 每个模块之间相互联系的紧密程度,模块之间联系越紧密,则耦合性越高,模块的独立性就越差!反之同理; 一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即‘高内聚’ !如:一个项目中有20个方法调用良好,但是要修改了其中一个,另外的19个都要进行修改,这就是高耦合!独立性太差! 现在的软件结构设计,都会要求“高内聚,低耦合”,来保证软件的高质量!mark! 8、对前后端联合开发 的技术原理(Ajax、Json)有一定认识,理解DOM、Xml概念, 熟悉前后台交互方式。 Ajax异步交互原理:Ajax其核心有JavaScript、XMLHTTPRequest、DOM对象组成,通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面。 Json:一般我用的比较多的是通过AJAX异步来获取JSON数据。 DOM:文档对象模型,一个网页中所有的东西都是dom节点,根节点是<html>,它可以无线嵌套。用来获取或设置文档中标签的属性,例如获取或者设置input表单的value值。 BOM:浏览器对象模型。用来获取或设置浏览器的属性、行为,例如:新建窗口、获取屏幕分辨率、浏览器版本号等。 XML:被设计用来传输和存储数据,被设计用来格式化和显示数据。仅仅是纯文本。 -前后台交互方式: 9、GET和POST请求的区别 GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。 GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码. 原文发布时间:2018年05月31日 作者:O_禾火_O 本文来源:奔三路学习网如需转载请联系原作者

优秀的个人博客,低调大师

java面试-深入理解JVM(六)——JVM性能调优实战

如何在高性能服务器上进行JVM调优? 为了充分利用高性能服务器的硬件资源,有两种JVM调优方案,它们都有各自的优缺点,需要根据具体的情况进行选择。 1. 采用64位操作系统,并为JVM分配大内存 我们知道,如果JVM中堆内存太小,那么就会频繁地发生垃圾回收,而垃圾回收都会伴随不同程度的程序停顿,因此,如果扩大堆内存的话可以减少垃圾回收的频率,从而避免程序的停顿。 因此,人们自然而然想到扩大内存容量。而32位操作系统理论上最大只支持4G内存,64位操作系统最大能支持128G内存,因此我们可以使用64位操作系统,并使用64位JVM,并为JVM分配更大的堆内存。但问题也随之而来。 堆内存变大后,虽然垃圾收集的频率减少了,但每次垃圾回收的时间变长。如果对内存为14G,那么每次Full GC将长达数十秒。如果Full GC频繁发生,那么对于一个网站来说是无法忍受的。 因此,对于使用大内存的程序来说,一定要减少Full GC的频率,如果每天只有一两次Full GC,而且发生在半夜, 那完全可以接受。 要减少Full GC的频率,就要尽量避免太多对象进入老年代,可以有以下做法: 确保对象都是“朝生夕死”的一个对象使用完后应尽快让他失效,然后尽快在新生代中被Minor GC回收掉,尽量避免对象在新生代中停留太长时间。 提高大对象直接进入老年代的门槛通过设置参数-XX:PretrnureSizeThreshold来提高大对象的门槛,尽量让对象都先进入新生代,然后尽快被Minor GC回收掉,而不要直接进入老年代。 注意:使用64位JDK的注意点 64位JDK支持更大的堆内存,但更大的堆内存会导致一次垃圾回收时间过长。 现阶段,64位JDK的性能普遍比32位JDK低。 堆内存过大无法在发生内存溢出时生成内存快照若将堆内存设为10G,那么当堆内存溢出时就要生成10G的大文件,这基本上是不可能的。 相同程序,64位JDK要比32位JDK消耗更大的内存 2. 使用32位JVM集群 针对于64位JDK种种弊端,我们更多选择使用32位JDK集群来充分利用高性能机器的硬件资源。 如何实现? 在一台服务器上运行多个服务器程序,这些程序都运行在32位的JDK上。然后再运行个服务器作为反向代理服务器,由它来实现负载均衡。由于32位JDK最多支持2G内存,因此每个虚拟结点的堆内存可以分配1.6G,一共运行10个虚拟结点的话,这台物理服务器可以拥有16G的堆内存。 有啥弊端? 多个虚拟节点竞争共享资源时容易出现问题如多个虚拟节点共同竞争IO操作,很可能会引起IO异常。 很难高效地使用资源池如果每个虚拟节点使用各自的资源池,那么无法实现各个资源池的负载均衡。如果使用集中式资源池,那么又存在竞争的问题。 每个虚拟节点最大内存为2G 别忘了直接内存也可能导致内存溢出! 问题描述 有个小型网站,使用32位JDK,堆1.6G。运行期间发现老是出现内存溢出。为了判断是否是堆内存溢出,在程序运行前添加参数:-XX:+HeapDumpOnOutOfMemeryError(添加这个参数后当堆内存溢出时就会输出异常日至)。但当再次发生内存溢出时,没有生成相关异常日志。从而可以判定,不是堆内存发生溢出。 问题分析 我们可以发现,在32位JDK中,将1.6G分配给了堆,还有一部分分配给了JVM的其它内存,只有少于0.4G的内存为非JVM内存。我们知道,如果使用了NIO,那么JVM会在JVM内存之外分配内存空间,这部分内存也叫“直接内存”。因此,如果程序中使用了NIO,那么就要小心“直接内存”不足时发生内存溢出异常了! 直接内存的垃圾回收过程 直接内存虽然不是JVM内存空间,但它的垃圾回收也有JVM负责。直接内存的垃圾回收发生在Full GC时,只有当老年代内存满时,垃圾收集器才会顺便收集一下直接内存中的垃圾。如果直接内存已满,但老年代没满,这时直接内存先是抛出异常,相应的catch块中调用System.gc()。由于System.gc()只是建议JVM回收,JVM可能不马上回收内存,那么这时直接内存就抛出内存溢出异常,使得程序终止。 JVM崩溃的原因 当内存溢出时,JVM仅仅会终止当前运行的程序,那么什么时候JVM会崩溃呢? 什么是异步请求? 我们知道,Web服务器和客户端采用HTTP通信,而HTTP底层采用TCP通信。异步通信就是当客户端向服务器发送一个HTTP请求后,将这个请求的TCP连接委托给其它线程,然后它转而做别的事,那条被委托的线程保持TCP连接,等待服务器的回信。当收到服务器回信后,再将收到的数据转交给刚才的线程。这个过程就是异步通信过程。 异步请求如何造成JVM崩溃? 如果一个Web应用使用了较多的异步请求(AJAX),每次主线程发送完请求后都将TCP连接交给一条新的线程去等待服务器回信,那么如果网络不流畅时,这些受委托的线程迟迟等不到服务器的回信,因此保持着TCP连接。当TCP连接过多时,超过JVM的承受能力,JVM就发生崩溃。 如何处理大对象? 大对象对于JVM来说是个噩耗。如果对象过大,当前新生代的剩余空间装不下它,那么就需要使用分配担保机制,将当前新生代的对象都复制到老年代中,给大对象腾出空间。分配担保涉及到大量的复制,因此效率很低。 那么,如果将大对象直接放入老年代,虽然避免了分配担保过程,但该对象只有当Full GC时才能被回收,而Full GC的代价是高昂的。如果大对象过多时,老年代很快就装满了,这时就需要进行Full GC,如果Full GC频率过高,程序就会变得很卡。 因此,对于大对象,有如下几种处理方法:1. 在写程序的时候尽量避免大对象从源头降低大对象的出现,尽量选择空间利用率较高的数据结构存储。2. 尽量缩短大对象的有效时间对象用完后尽快让它失效,好让垃圾收集器尽快将他回收,避免因在新生代呆的时间过长而进入老年代。

优秀的个人博客,低调大师

java面试-深入理解JVM(四)——对象内存的分配策略

Java所承诺的自动内存管理主要是针对对象内存的回收和对象内存的分配。 在Java虚拟机的五块内存空间中,程序计数器、Java虚拟机栈、本地方法栈内存的分配和回收都具有确定性,一般在编译阶段就能确定需要分配的内存大小,并且由于都是线程私有,因此它们的内存空间都随着线程的创建而创建,线程的结束而回收。也就是这三个区域的内存分配和回收都具有确定性,垃圾回收器不需要在这里花费太大的精力。 而Java虚拟机中的方法区因为是用来存储类信息、常量、静态变量,这些数据的变动性较小,因此不是Java内存管理重点需要关注的区域。 而对于堆,所有线程共享,所有的对象都需要在堆中创建和回收。虽然每个对象的大小在类加载的时候就能确定,但对象的数量只有在程序运行期间才能确定,因此堆中内存的分配具有较大的不确定性。此外,对象的生命周期长短不一,因此需要针对不同生命周期的对象采用不同的内存回收算法,增加了内存回收的复杂性。 综上所述:Java自动内存管理最核心的功能是堆内存中对象的分配与回收。 对象优先在Eden区中分配 目前主流的垃圾收集器都会采用分代回收算法,因此需要将堆内存分为新生代和老年代。 在新生代中为了防止内存碎片问题,因此垃圾收集器一般都选用“复制”算法。因此,堆内存的新生代被进一步分为:Eden区+Survior1区+Survior2区。 每次创建对象时,首先会在Eden区中分配。若Eden区已满,则在Survior1区中分配。若Eden区+Survior1区剩余内存太少,导致对象无法放入该区域时,就会启用“分配担保”,将当前Eden区+Survior1区中的对象转移到老年代中,然后再将新对象存入Eden区。 大对象直接进入老年代 所谓“大对象”就是指一个占用大量连续存储空间的对象,如数组。 当发现一个大对象在Eden区+Survior1区中存不下的时候就需要分配担保机制把当前Eden区+Survior1区的所有对象都复制到老年代中去。我们知道,一个大对象能够存入Eden区+Survior1区的概率比较小,发生分配担保的概率比较大,而分配担保需要涉及到大量的复制,就会造成效率低下。因此,对于大对象我们直接把他放到老年代中去,从而就能避免大量的复制操作。那么,什么样的对象才是“大对象”呢? 通过-XX:PretrnureSizeThreshold参数设置大对象 该参数用于设置大小超过该参数的对象被认为是“大对象”,直接进入老年代。注意:该参数只对Serial和ParNew收集器有效。 生命周期较长的对象进入老年代 老年代用于存储生命周期较长的对象,那么我们如何判断一个对象的年龄呢? 新生代中的每个对象都有一个年龄计数器,当新生代发生一次MinorGC后,存活下来的对象的年龄就加一,当年龄超过一定值时,就将超过该值的所有对象转移到老年代中去。 使用-XXMaxTenuringThreshold设置新生代的最大年龄 设置该参数后,只要超过该参数的新生代对象都会被转移到老年代中去。 相同年龄的对象内存超过Survior内存一半的对象进入老年代 如果当前新生代的Survior中,年龄相同的对象的内存空间总和超过了Survior内存空间的一半,那么所有年龄相同的对象和超过该年龄的对象都被转移到老年代中去。无需等到对象的年龄超过MaxTenuringThreshold才被转移到老年代中去。 “分配担保”策略详解 当垃圾收集器准备要在新生代发起一次MinorGC时,首先会检查“老年代中最大的连续空闲区域的大小 是否大于 新生代中所有对象的大小?”,也就是老年代中目前能够将新生代中所有对象全部装下? 若老年代能够装下新生代中所有的对象,那么此时进行MinorGC没有任何风险,然后就进行MinorGC。 若老年代无法装下新生代中所有的对象,那么此时进行MinorGC是有风险的,垃圾收集器会进行一次预测:根据以往MinorGC过后存活对象的平均数来预测这次MinorGC后存活对象的平均数。 如果以往存活对象的平均数小于当前老年代最大的连续空闲空间,那么就进行MinorGC,虽然此次MinorGC是有风险的。 如果以往存活对象的平均数大于当前老年代最大的连续空闲空间,那么就对老年代进行一次Full GC,通过清除老年代中废弃数据来扩大老年代空闲空间,以便给新生代作担保。 这个过程就是分配担保。 注意:1. 分配担保是老年代为新生代作担保;2. 新生代中使用“复制”算法实现垃圾回收,老年代中使用“标记-清除”或“标记-整理”算法实现垃圾回收,只有使用“复制”算法的区域才需要分配担保,因此新生代需要分配担保,而老年代不需要分配担保。

优秀的个人博客,低调大师

java程序员面试——Java并发编程知识点总结 ...

线程的状态 初始态:NEW 创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态。 运行态:RUNNABLE 在Java中,运行态包括就绪态 和 运行态。 就绪态 该状态下的线程已经获得执行所需的所有资源,只要CPU分配执行权就能运行。 所有就绪态的线程存放在就绪队列中。 运行态 获得CPU执行权,正在执行的线程。 由于一个CPU同一时刻只能执行一条线程,因此每个CPU每个时刻只有一条运行态的线程。 阻塞态 当一条正在执行的线程请求某一资源失败时,就会进入阻塞态。 而在Java中,阻塞态专指请求锁失败时进入的状态。 由一个阻塞队列存放所有阻塞态的线程。 处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执行。 PS:锁、IO、Socket等都资源。 等待态 当前线程中调用wait、join、park函数时,当前线程就会进入等待态。 也有一个等待队列存放所有等待态的线程。 线程处于等待态表示它需要等待其他线程的指示才能继续运行。 进入等待态的线程会释放CPU执行权,并释放资源(如:锁) 超时等待态 当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就会进入该状态; 它和等待态一样,并不是因为请求不到资源,而是主动进入,并且进入后需要其他线程唤醒; 进入该状态后释放CPU执行权 和 占有的资源。 与等待态的区别:到了超时时间后自动进入阻塞队列,开始竞争锁。 终止态 线程执行结束后的状态。 线程状态转换图 初始态——>就绪态 当线程对象调用start()方法时就会进入就绪态,若就绪队列没有线程,则直接进入运行态。 就绪态——>运行态 由系统调用完成。 就绪态<——运行态 调用Thread.yield()函数 由系统调用完成(当线程时间片用完) 运行态——>阻塞态 当线程请求锁失败时进入阻塞态。 阻塞态——>就绪态 阻塞队列中的线程会不断检查锁是否可用,一旦可用就进入就绪队列。 运行态——>等待态 调用Object.wait()方法 wait方法必须在同步块内部; 必须由同步块的锁对象调用; 必须由notify方法和wait方法必须由同一个锁对象调用 调用Thread.join()方法 调用LockSupport.park()方法 等待态——>就绪态 某一个线程调用了 锁对象.notify()方法,并且等待的线程并不需要锁 等待态——>阻塞态 锁对象.notify()方法,并且等待的线程需要锁同步。 注意点 wait()方法会释放CPU执行权 和 占有的锁。 sleep(long)方法仅释放CPU使用权,锁仍然占用;线程被放入超时等待队列,与yield相比,它会使线程较长时间得不到运行。 yield()方法仅释放CPU执行权,锁仍然占用,线程会被放入就绪队列,会在短时间内再次执行。 wait和notify必须配套使用,即必须使用同一把锁调用; wait和notify必须放在一个同步块中 调用wait和notify的对象必须是他们所处同步块的锁对象。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。