• [技术干货] JVM-垃圾回收算法和垃圾回收器[转载]
    一、GC-垃圾回收:stop-the-world(stw): 他会在任何一种GC算法中发生。stw意味着jvm因为需要执行GC而停止了应用程序的执行。当stw发生时,出GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成。GC优化的很多时候,就是减少stw的发生。需要注意的是,jvm gc只回收堆和方法区内的对象,而栈区的数据,在超出作用域后会被jvm自动释放掉,所有其不再jvm gc的管理范围内。jvm -gc 如何判断对象可以被回收了?对象没有应用作用域发生未捕获异常程序在作用域正常执行完毕程序执行了System.exit();程序发生意外终止(被杀线程等)在java程序中不能显示的分配和注销缓存,因为这些事情jvm都帮我们做了,那就是GC.有些时候我们可以将相关对象设置成null来试图显示的清楚缓存,但是并不是设置成null就会一定被标记为可回收,有可能会发生逃逸。将对象设置成null至少没有什么坏处,但是使用System.gc()便不可取了,使用System.gc()的时候并不是马上执行GC操作,而是会等待一段时间,甚至不执行,而且System.gc()如果别执行,会出发Full GC,这费城影响性能。GC什么时候执行:eden区空间不够存放新对象的时候,执行minor gc。 升到年老代的对象大于老年代的剩余空间时执行full gc,或者小于的时候,被 HandlePromotionFailure 参数强制Full GC。 调优主要是减少Full GC 的触发次数,可以通过NewRatio 控制新生代转老年代的比例,通过MaxTurningThreshold 设置对象进入老年代的年龄阀值。按代的垃圾回收机制:新生代(Young generation):绝大多数的最新被创建的对象都会被分配到这里,由于大部分在创建后很快变得不可达,很多对象别创建在新生代,然后消失。对象从这个区域消失的过程,我们称之为 Minor GC老年代(old generation): 对象没有变得不可达,并且从新生代周期中存活了下来,会被拷贝到这里。其区域分配的空间要比新生代多。也正是由于其相对较大的空间,发生在老年代的GC次数要比新生代少得多。对象从老年代消失的过程称之为: Major GC, 或者 Full GC.持久代(Permanent generation):也称之为方法区,用于保存类常量以及字符串常量,注意,这个区域不是用于存储那些从老年代存活下来的对象,这个区域也可能发生GC, 发生在这个区域的GC事件也被算作Major GC,只不过在这个区域发生GC 的条件非诚严苛,必须符合以下三种条件:所有实例被回收加载该类的ClassLoader被回收Class 对象无法通过任何途径访问(包括反射)如果老年代要引用新生代的对象,会发生什么呢?为了解决这个问题,老年代中存在一个 card table ,它是一个512byte大小的块。所有老年代的对象指向新生代对象的引用都会被记录在这个表中。当针对新生代执行GC的时候,只需要查询 card table 来决定是否可以被回收,而不用查询整个老年代。这个 card table 由一个write barrier 来管理。write barrier给GC带来了很大的性能提升,虽然由此可能带来一些开销,但完全是值得的。默认的新生代和老年代所占空间的比例为1:2新生代空间的构成和逻辑:分为三个部分: 一个伊甸园空间(eden), 两个幸存者空间)(From Survivor, To Survivor)默认比例: Eden:From:to = 8:1:1每个空间执行顺序:绝大多数刚刚被创建的对象会存放在伊甸园EDEN空间在eden空间执行第一次gc(minor gc)后,存活的对象被移动到其中的一个幸存者区此后,每次Eden空间执行gc后,存活的对象都会被堆积在同一个幸存者空间。当一个幸存者空间饱和,还存在存活的对象会被移动到另一个幸存者空间,然后会清空已经饱和的那个幸存者空间在以上步骤中重复N次(N=MAXTenuringThreshold(年龄阀值设定,默认15))依然存活的对象,就会别移动到老年代从上面的步骤可以发现,两个幸存者空间,必须有一个是保持空的,如果两个幸存者空间都有数据,或者两个都是空的,那一定是你的系统出现了某种错误。我们需要重点记住的是,对象在刚刚被创建之后,是保存在Eden区的,哪些长期存活的对象会经由幸存者空间转到老年代空间。也有例外的情况,对于一些比较大的对象(需要分配连续比较大的空间)则直接进入到老年代,一般在幸存者空间不足的情况下发生。老年代空间的构成与逻辑:老年代空间的构成其实很简单,他不像新生代那样划分为几个区域,他只有一个区域,里面存储的对象并不像新生代空间绝大部分都是朝闻道,夕死矣。这里的对象几乎都是从Survivor空间中熬过来的,他们绝不会轻易狗带。因此FULL GC 发生的次数不会有minor gc那么频繁,并且做一次full gc的时间比minor gc要更长(约10倍)二、GC算法:1. 根搜索算法(可达性分析):从GCROOT开始,寻找对应的引用节点,找到这个节点后,继续寻找这个节点的引用节点。当所有的引用节点寻找完毕后,剩余的节点则被认为是没有被引用到的节点,及无用的节点。目前java中可以作为GCroot的对象有: 虚拟机栈中引用的对象(本地变量表),方法区中静态属性引用的对象,方法区中常量引用的对象,本地方法栈中引用的对象(native)2. 标记-清除算法:标记-清除算法采用从根集合进行扫描,对存活的对象进行标记,标记完毕后,在扫描整个空间中未标记的对象进行直接回收。标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活的对象比较多的情况下极为高效,但是由于标记-清除算法直接回收不存活的对象,并没有对存活的对象进行整理,因此会导致内存碎片。3. 复制算法:复制算法将内存划分为两个区间,使用此算法时,所有的动态分配的对象都只能分配在其中一个区间,而另一个区间是闲置的。复制算法采用从根集合扫描,将存活对象复制到空闲区间,当扫描完毕活动区间后,会将活动区间一次性全部回收,此时原本的空闲区间变成了活动区间,下次gc的时候会重复刚才的操作,以此循环。复制算法在存活对象较少的时候,极为高效,但是带来的成本是牺牲一半的内存空间用于对象的移动,所以复制算法使用的场景,必须是对象的存活率非常低才行。4. 标记-整理算法:标记-整理算法采用和标记-清除算法一样的方式进行对象的标记,清除,但是在回收不存活对象占用的空间后,会见给所有的存活的对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法之上,又进行了对象的移动排序整理,因此成本更高,但却解决了内存碎片的问题,JVM 为了优化内存得回收,是用来分代回收的方式,对于新生代的内存回收,主要采用复制算法,而对于老年代的回收,大多采用标记整理算法。三、垃圾回收器需要注意的是,每一个回收器都存在stw的问题,只不过各个回收器在stw时间优化程度、算法的不同,可根据自身需求选择适合的回收器。1.Serial(-XX: + UseSerialGC)从名字可以看出,这是一个串行的垃圾回收器,这也是java虚拟机中最基本,历史最悠久的收集器,在jdk1.3之前是java虚拟机新生代收集器的唯一选择,目前也是ClientVM 下ServerVM4核4gb以下机器的默认垃圾回收器,Serial收集器并不是只能使用一个CPU进行收集,而是当jvm需要进行垃圾回收的时候,需暂停所有的用户线程,直到回收结束。使用算法: 复制算法。Serial收集器虽然是最老的,但是它对于限定单个CPU的环境来说,由于没有线程交互的开销,专心做垃圾收集,所以它在这种情况下是相对于其他收集器中最高效的。2. SerialOld(-XX: + UseSerialGC)SerialOld是Serial收集器的老年代收集器版本,它同样是一个单线程收集器,这个收集器目前主要用于Client模式下使用。如果在Server模式下,它主要还有两大用途:一个是在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用,另外一个就是作为CMS收集器的后备预案,如果CMS出现Concurrent Mode Failure,则SerialOld将作为后备收集器。使用算法:标记 - 整理算法3. ParNew(-XX: +UseParNewGC)ParNew其实就是Serial收集器的多线程版本。除了Serial收集器外,只有它能与CMS收集器配合工作。使用算法: 复制算法ParNew 是许多运行在Server模式下的JVM的首选的新生代收集器,但是在单cpu的情况下,他的效率远远低于Serial收集器,所以一定要注意使用场景。4. ParallelScavenge(-XX:+UseParallelGC)ParallelScavenge又被称为吞吐量优先收集器,和ParNew 收集器类似,是一个新生代收集器使用算法: 复制算法ParallelScavenge收集器的目的是打到一个可控的吞吐量,所谓吞吐量就是cpu用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。如果虚拟机总共运行了100分钟,其中垃圾回收用了1分钟,那么吞吐量就是99%所以这个收集器适合在后台运算而不需要很多交互的任务。接下来看看两个用于准备控制吞吐量的参数 1,-XX:MaxGCPauseMills(控制最大垃圾收集的时间) 设置一个大于0的毫秒数,收集器尽可能地保证内存回收不超过设定值。但是并不是设置地越小就越快。GC停顿时间缩短是以缩短吞吐量和新生代空间来换取的。 2,-XX:GCTimeRatio(设置吞吐量大小) 设置一个0-100的整数,也就是垃圾收集时间占总时间的比率,相当于吞吐量的倒数。5. ParallelOld(-XX: + UseParallelOldGC)ParallelOld 是并行收集器,和SerialOld 一样,是一个老年代收集器,是老年代吞吐量优先的一个收集器,这个收集器在JDK1.6之后才开始提供的,再次之前,ParallelScavenge只能选择SerialOld来作为其老年代的收集器,这严重拖累了ParallelScavenge的整体速度,而ParallelOld出现了之后,吞吐量有限收集器才名副其实使用算法: 标记-整理算法在注重吞吐量与CPU数量大于1 的情况下,都可以优先考虑ParallelScavenge + ParallelOld收集器6. CMS(-XX:UseConcMarkSweepGC)CMS是一个老年代收集器,全称Concurrent Low Pause Collector, 是JDK1.4以后开始引用的心GC收集器,在jdk5,jdk6中得到了进一步的改进。他是对于响应时间的重要性需求大于吞吐量要求的收集器,对于要求服务器响应速度高的情况下,使用CMS非常合适。CMS的一大特点,就是用两次短暂的暂定来代替串行或者并行标记整理算法时候的长暂停使用算法:标记-清理执行过程如下:初始标记(STW initial mark):在这个阶段,需要虚拟机停顿在正在执行的应用线程,官方叫法叫做STW,这个过程从根对象扫描直接关联的对象,并做标记,这个过程会很快完成。并发标记(Concurrent marking) :这个阶段紧随初始标记阶段,在初始标记的基础上继续向下追溯标记,注意这里是并发标记,标识用户线程可以和GC线程一起并发执行,这个阶段不会暂停用户线程并发预清理(Concurrent precleaning):这个阶段仍然是并发的,jvm查找正在执行并发标记阶段时候进入老年代的对象(可能这是会有对象从新生代晋升到老年代,或被分配到老年代)通过重新扫描,减少在一个阶段重新标记的工作,因为下一个阶段会stw重新标记(stw remark): 这个阶段会再次暂停正在执行的应用线程,重新从根对象开始查找并标记并发阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)并处理对象关联,这一次耗时回避“初始标记”更长,并且这个阶段可以并行标记。并发清理(Concurrent sweeping): 这个阶段是并发的,应用程序和GC清理线程可以一起并发执行并发重置(Concurrent reset):这个阶段仍然是并发的,重置CMS收集器的数据结构,等待下一次垃圾回收CMS:缺点:内存碎片;由于使用了标记-清理算法,导致内存空间中会产生内存碎片,不过CMS收集器做了一些小的优化,就是把未分配的空间汇总成一个列表,当有JVM需要分配内存空间的时候,会搜索这个列表找到符合条件的空间来存储这个对象,但是内存碎片的问题仍然存在,如果一个对象需要三块连续的空间来存储,因为内存碎片的问题,找不到这样的空间,就会导致full gc.需要更多的CPU资源:由于使用了并发处理,很多情况下都是GC线程和用户线程并发执行的,这样就需要占用更多的CPU资源,也是牺牲了一定吞吐量的原因。需要更大的堆空间:因为CMS标记阶段用用程序的线程还是执行的,那么就会有堆空间继续分配的问题,为了保障CMS在回收堆空间之前还有空间分配给新加入的对象,必须预留一部分空间,cms默认在老年代空间使用68%的时候启动垃圾回收,可以通过-XX:CMSinitiatingOccupancyFraction=n来设置这个阀值。7. garbageFirst(G1)G1收集器是jdk1.7提供的一个新的收集器,是当今收集器技术发展的最前沿成果之一。G1是一款面向服务端应用的垃圾收集器,Hotspot开发团队赋予它的使命是未来可以替换掉cms.G1具备以下特点:并行与并发: G1能充分利用多CPU,多核心环境下的硬件优势,使用多个CPU来缩短STW停顿的时间,部分其他收集器原本需要停顿java线程执行的G1动作,G1收集器仍然可以通过并发的方式让java程序继续执行。分代收集:与其他收集器一样,分代概念在G1中仍然得以保留,虽然G1可以不需要其他收集器配合就能单独管理整个GC堆,但他能够采取不同的方式去处理新创建的对象和已经存活了一段时间。熬过多个gc的旧对象已获得更好的收集效果空间整合:与CMS的标记-清除算法不同,G1收集器从整体上看是基于标记-整理算法实现的,从局部(两个region)上看是基于复制算法实现的,但无论如何,两种算法都意味着g1运行期间不会产生内存空间碎片,收集后能够提供规整的可用内存。这种特性有利于程序的长时间运行, 分配大对象时不会因为无法找到连续的内存空间而提前触发下一次GC可预测的停顿:这是G1相比cms的另一大优势,降低停顿时间是G1和cms的共同关注点,但是G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时java(RTSJ)的垃圾收集器的特征了。整理一下新生代和老年代的收集器。新生代收集器:Serial (-XX:+UseSerialGC)ParNew(-XX:+UseParNewGC)ParallelScavenge(-XX:+UseParallelGC)G1 收集器老年代收集器:SerialOld(-XX:+UseSerialOldGC)ParallelOld(-XX:+UseParallelOldGC)CMS(-XX:+UseConcMarkSweepGC)G1 收集器
  • [java] 【华为matepad 11】【硬件aec】华为matepad 11硬件aec的效果非常差
    【功能模块】音频模块【操作步骤&问题现象】1、加入会议,远端播放声音2、本端华为matepad 11使用硬件aec3、远端听到回声,硬件aec完全没处理掉回声4、抓去的系统log,显示是有硬件aec音效的:effects client='Acoustic Echo Canceler'5、使用java接口判断是否支持硬件aec,也是返回支持硬件aec(代码见下边截图)【问题点】1、从最终的结果来看,华为matepad 11明明不支持硬件aec(效果非常差),为何调用系统接口返回的是true?2、如果不是从代码中的接口获取是否支持硬件aec,那应该如何正确的判断安卓设备是否支持硬件aec?3、从目前的测试结果来看,非常多的安卓机型存在以下问题:明明不支持硬件aec(效果非常差),但是调用系统接口却返回支持硬件aec硬件aec无法关闭,调用java接口关闭硬件aec后,硬件aec仍然在生效(因为麦克风返回的数据已经没有回声或者回声被处理过一些但仍有残留)import android.media.audiofx.AcousticEchoCanceler;AcousticEchoCanceler aec = AcousticEchoCanceler.create(audioSession);aec.setEnabled(false);【截图信息】
  • [互动交流] 【Phoenix产品】【客户端认证功能】同一个Java 进程内先创建了es的客户端之后,Phoenix客户端获取连接异常
    【功能模块】【操作步骤&问题现象】1、同一个Java 进程内 先调用一下es服务(开启了kerberos认证)2、再调用一下Phoenix服务【截图信息】【日志信息】(可选,上传日志内容或者附件)org.apache.zookeeper.KeeperException$SystemErrorException: KeeperErrorCode = SystemError for /hbase    at org.apache.phoenix.util.ServerUtil.parseServerException(ServerUtil.java:138)    at org.apache.phoenix.query.ConnectionQueryServicesImpl.ensureTableCreated(ConnectionQueryServicesImpl.java:1204)    at org.apache.phoenix.query.ConnectionQueryServicesImpl.createTable(ConnectionQueryServicesImpl.java:1501)    at org.apache.phoenix.query.DelegateConnectionQueryServices.createTable(DelegateConnectionQueryServices.java:119)    at org.apache.phoenix.schema.MetaDataClient.createTableInternal(MetaDataClient.java:2721)    at org.apache.phoenix.schema.MetaDataClient.createTable(MetaDataClient.java:1114)    at org.apache.phoenix.compile.CreateTableCompiler$1.execute(CreateTableCompiler.java:192)    at org.apache.phoenix.jdbc.PhoenixStatement$2.call(PhoenixStatement.java:409)    at org.apache.phoenix.jdbc.PhoenixStatement$2.call(PhoenixStatement.java:392)    at org.apache.phoenix.call.CallRunner.run(CallRunner.java:53)    at org.apache.phoenix.jdbc.PhoenixStatement.executeMutation(PhoenixStatement.java:391)    at org.apache.phoenix.jdbc.PhoenixStatement.executeMutation(PhoenixStatement.java:379)    at org.apache.phoenix.jdbc.PhoenixStatement.executeUpdate(PhoenixStatement.java:1811)    at org.apache.phoenix.query.ConnectionQueryServicesImpl$12.call(ConnectionQueryServicesImpl.java:2573)    at org.apache.phoenix.query.ConnectionQueryServicesImpl$12.call(ConnectionQueryServicesImpl.java:2536)    at org.apache.phoenix.util.PhoenixContextExecutor.call(PhoenixContextExecutor.java:76)    at org.apache.phoenix.query.ConnectionQueryServicesImpl.init(ConnectionQueryServicesImpl.java:2536)    at org.apache.phoenix.jdbc.PhoenixDriver.getConnectionQueryServices(PhoenixDriver.java:264)    at org.apache.phoenix.jdbc.PhoenixEmbeddedDriver.createConnection(PhoenixEmbeddedDriver.java:150)    at org.apache.phoenix.jdbc.PhoenixDriver.connect(PhoenixDriver.java:230)    at java.sql.DriverManager.getConnection(DriverManager.java:664)    at java.sql.DriverManager.getConnection(DriverManager.java:208)    at com.dtwave.ai.engine.freyr.strategy.phoenix.plugin.PhoenixExecutorImpl.lambda$getConnection$0(PhoenixExecutorImpl.java:123)    ... 82 common frames omittedCaused by: org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=2, exceptions:2022-03-29T03:03:45.889Z, RpcRetryingCaller{globalStartTime=1648523025126, pause=50, maxAttempts=2}, org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=2, exceptions:2022-03-29T03:03:45.197Z, RpcRetryingCaller{globalStartTime=1648523025126, pause=50, maxAttempts=2}, java.io.IOException: org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /hbase2022-03-29T03:03:45.888Z, RpcRetryingCaller{globalStartTime=1648523025126, pause=50, maxAttempts=2}, java.io.IOException: org.apache.zookeeper.KeeperException$SystemErrorException: KeeperErrorCode = SystemError for /hbase2022-03-29T03:03:46.041Z, RpcRetryingCaller{globalStartTime=1648523025126, pause=50, maxAttempts=2}, org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=2, exceptions:2022-03-29T03:03:45.989Z, RpcRetryingCaller{globalStartTime=1648523025939, pause=50, maxAttempts=2}, java.io.IOException: org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /hbase2022-03-29T03:03:46.040Z, RpcRetryingCaller{globalStartTime=1648523025939, pause=50, maxAttempts=2}, java.io.IOException: org.apache.zookeeper.KeeperException$SystemErrorException: KeeperErrorCode = SystemError for /hbase    at org.apache.hadoop.hbase.client.RpcRetryingCallerImpl.callWithRetries(RpcRetryingCallerImpl.java:152)    at org.apache.hadoop.hbase.client.HBaseAdmin.executeCallable(HBaseAdmin.java:3272)    at org.apache.hadoop.hbase.client.HBaseAdmin.executeCallable(HBaseAdmin.java:3264)    at org.apache.hadoop.hbase.client.HBaseAdmin.tableExists(HBaseAdmin.java:472)    at org.apache.phoenix.query.ConnectionQueryServicesImpl.ensureTableCreated(ConnectionQueryServicesImpl.java:1105)    ... 103 common frames omittedCaused by: org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=2, exceptions:2022-03-29T03:03:45.989Z, RpcRetryingCaller{globalStartTime=1648523025939, pause=50, maxAttempts=2}, java.io.IOException: org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /hbase2022-03-29T03:03:46.040Z, RpcRetryingCaller{globalStartTime=1648523025939, pause=50, maxAttempts=2}, java.io.IOException: org.apache.zookeeper.KeeperException$SystemErrorException: KeeperErrorCode = SystemError for /hbase    at org.apache.hadoop.hbase.client.RpcRetryingCallerImpl.callWithRetries(RpcRetryingCallerImpl.java:152)    at org.apache.hadoop.hbase.client.HTable.get(HTable.java:384)    at org.apache.hadoop.hbase.client.HTable.get(HTable.java:358)    at org.apache.hadoop.hbase.MetaTableAccessor.getTableState(MetaTableAccessor.java:1124)    at org.apache.hadoop.hbase.MetaTableAccessor.tableExists(MetaTableAccessor.java:446)    at org.apache.hadoop.hbase.client.HBaseAdmin$6.rpcCall(HBaseAdmin.java:475)    at org.apache.hadoop.hbase.client.HBaseAdmin$6.rpcCall(HBaseAdmin.java:472)    at org.apache.hadoop.hbase.client.RpcRetryingCallable.call(RpcRetryingCallable.java:58)    at org.apache.hadoop.hbase.client.RpcRetryingCallerImpl.callWithRetries(RpcRetryingCallerImpl.java:109)    ... 107 common frames omittedCaused by: java.io.IOException: org.apache.zookeeper.KeeperException$SystemErrorException: KeeperErrorCode = SystemError for /hbase    at org.apache.hadoop.hbase.client.ConnectionImplementation.get(ConnectionImplementation.java:2147)    at org.apache.hadoop.hbase.client.ConnectionImplementation.locateMeta(ConnectionImplementation.java:820)    at org.apache.hadoop.hbase.client.ConnectionImplementation.locateRegion(ConnectionImplementation.java:787)    at org.apache.hadoop.hbase.client.HRegionLocator.getRegionLocation(HRegionLocator.java:64)    at org.apache.hadoop.hbase.client.RegionLocator.getRegionLocation(RegionLocator.java:58)    at org.apache.hadoop.hbase.client.RegionLocator.getRegionLocation(RegionLocator.java:47)    at org.apache.hadoop.hbase.client.RegionServerCallable.prepare(RegionServerCallable.java:223)    at org.apache.hadoop.hbase.client.RpcRetryingCallerImpl.callWithRetries(RpcRetryingCallerImpl.java:107)    ... 115 common frames omittedCaused by: org.apache.zookeeper.KeeperException$SystemErrorException: KeeperErrorCode = SystemError for /hbase    at org.apache.zookeeper.KeeperException.create(KeeperException.java:97)    at org.apache.zookeeper.KeeperException.create(KeeperException.java:54)    at org.apache.hadoop.hbase.zookeeper.ReadOnlyZKClient$ZKTask$1.exec(ReadOnlyZKClient.java:209)    at org.apache.hadoop.hbase.zookeeper.ReadOnlyZKClient.run(ReadOnlyZKClient.java:356)    ... 1 common frames omitted
  • [技术干货] 常用方法和封装详情
    这篇文章主要介绍了JavaScript常用方法和封装详情,文章围绕JavaScript的方法和封装相关资料展开详情,具有一定的参考价值,需要的小伙伴可以参考一下目录• 1.字符串相关 • 1.1 format方法 • 2.数组相关 • 1.2 forEach(callback,context) 操作数组中的每一个元素 • 1.3 indexOf(searchvalue,fromindex) 查询数组中某一个值的下标 • 3.数组封装 1.字符串相关1.1 format方法在各种编程语言中,字符串的format方法是比较常见的,以下通过js扩展的方式,实现了js版本的format方法。目前貌似还没有浏览器支持这一个方法。12345678if(!String.prototype.format ){    String.prototype.format = function() {        var e = arguments;        return this.replace(/{(\d+)}/g,function(t, n) {            return typeof e[n] != "undefined" ? e[n] : t;        })    };} 例子:12var template = "今天的天气很{0},大家一起去{1}!";alert(template.format("晴朗","郊游"));效果:2.数组相关1.2 forEach(callback,context) 操作数组中的每一个元素ie9以上的浏览器,以及其他非IE浏览器都支持这一方法。以下是兼容性的扩展写法:12345678910111213141516171819/**    forEach除了接受一个必须的回调函数参数,还可以接受一个可选的上下文参数(改变回调函数里面的this指向)(第2个参数)。*/if (!Array.prototype.forEach && typeof Array.prototype.forEach !== "function") {    Array.prototype.forEach = function(callback, context) {       // 遍历数组,在每一项上调用回调函数,这里使用原生方法验证数组。       if (Object.prototype.toString.call(this) === "[object Array]") {           var i,len;           //遍历该数组所有的元素           for (i = 0, len = this.length; i < len; i++) {               if (typeof callback === "function"  && Object.prototype.hasOwnProperty.call(this, i)) {                   if (callback.call(context, this[i], i, this) === false) {                       break; // or return;                   }               }           }       }    };}例子:12345678910var drinks = ['雪碧','可乐','脉动','红牛','农夫山泉'];         var context = {    str1 : '【',    str2 : '】'};         drinks.forEach(function(item){    console.log(this.str1 + item + this.str2);},context);效果:这个方法在各大浏览器都得到了较好的支持。1.3 indexOf(searchvalue,fromindex) 查询数组中某一个值的下标ie9以上的浏览器,以及其他非IE浏览器都支持这一方法。以下是兼容性的扩展写法:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162//获取某元素在数组中第一次出现的下标if (!Array.prototype.indexOf) {  Array.prototype.indexOf = function(searchElement, fromIndex) {    var k;    // 1. Let O be the result of calling ToObject passing    //    the this value as the argument.    if (this == null) {      throw new TypeError('"this" is null or not defined');    }      var O = Object(this);      // 2. Let lenValue be the result of calling the Get    //    internal method of O with the argument "length".    // 3. Let len be ToUint32(lenValue).    var len = O.length >>> 0;      // 4. If len is 0, return -1.    if (len === 0) {      return -1;    }      // 5. If argument fromIndex was passed let n be    //    ToInteger(fromIndex); else let n be 0.    var n = +fromIndex || 0;      if (Math.abs(n) === Infinity) {      n = 0;    }      // 6. If n >= len, return -1.    if (n >= len) {      return -1;    }      // 7. If n >= 0, then Let k be n.    // 8. Else, n<0, Let k be len - abs(n).    //    If k is less than 0, then let k be 0.    k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);      // 9. Repeat, while k < len    while (k < len) {      // a. Let Pk be ToString(k).      //   This is implicit for LHS operands of the in operator      // b. Let kPresent be the result of calling the      //    HasProperty internal method of O with argument Pk.      //   This step can be combined with c      // c. If kPresent is true, then      //    i.  Let elementK be the result of calling the Get      //        internal method of O with the argument ToString(k).      //   ii.  Let same be the result of applying the      //        Strict Equality Comparison Algorithm to      //        searchElement and elementK.      //  iii.  If same is true, return k.          if (k in O && O[k] === searchElement) {            return k;          }          k++;        }        return -1;      };    }例子:12var index = drinks.indexOf('雪碧');alert(index);//0类似的还有lastIndexOf,用于获取数组中某个元素最后一次出现的位置。如果数组没有这个元素,则返回-1。该方法的实现:12345678910111213141516171819202122232425262728293031323334353637//获取某元素在数组中最后一次出现的下标if (!Array.prototype.lastIndexOf) {      Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {    'use strict';      if (this === void 0 || this === null) {      throw new TypeError();    }      var n, k,        t = Object(this),        len = t.length >>> 0;    if (len === 0) {      return -1;    }      n = len - 1;    if (arguments.length > 1) {      n = Number(arguments[1]);      if (n != n) {        n = 0;      }      else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {        n = (n > 0 || -1) * Math.floor(Math.abs(n));      }    }      for (k = n >= 0          ? Math.min(n, len - 1)          : len - Math.abs(n); k >= 0; k--) {      if (k in t && t[k] === searchElement) {        return k;      }    }    return -1;  };}通过这两个方法,我们可以来做一些有意思的事情了。比如,判断一个对象是否为数组?IE9 以上的浏览器,已经支持通过Array.isArray()来验证一个对象是否为数组了。比如:123var result = Array.isArray([]);alert(typeof []);//objectalert(result); //true那么,如果我们自己来实现,又该如何做呢?下面给出一个简单思路,简单模拟一下这个过程:1234567//首先,让我们来看一看数组的构造器是咋样的?console.log([].constructor.toString());  /*    打印出来是这样的:    function Array() { [native code] }*/于是便有了12345678910 var Array = function(){  }  Array.isArray = function(obj){    return obj.constructor.toString().indexOf('Array') != -1;}  var result = Array.isArray([]); alert(result); //true虽然取巧了点,不过目的确实达到了。3.数组封装通过数组的一些基本方法,我们可以开始自己模拟一下java中的ArrayList了代码如下:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120//模拟ArrayListfunction ArrayList(){    var arr = []; //用于保存数据的数组    var length = 0; //数组的长度,默认为0         /**     * 判断是否为空     */    this.isEmpty = function(){        return length == 0;    }         /**     * 获取列表长度     */         this.size = function(){        return length;    }         /**     * 判断对象中是否包含给定对象    */     this.contains = function(obj){        if(arr.indexOf(obj) != -1){            return true;        }        return false;    }         /**     * 新增    */   this.add = function(obj){    length = length + 1;    arr.push(obj);   }       /**    * 删除    * 参数1  obj : 需要删除的元素    * 参数2  deleteAll: 是否全部删除,否则默认删除第一个匹配项    */   this.remove = function(obj,deleteAll){        var len = arr.length;        for(var i = 0 ;i < len ;i++){            if(arr[i] == obj){                arr.splice(i,1);                length = length - 1;                if(!deleteAll){                    break;                }            }        }   }           /**    * 根据索引获取对应的元素    */   this.get = function(index){    if(index > length - 1){        return null;    }    return arr[index];   }       /**    * 获取列表数组    */   this.toArray = function(){     return arr;   }       /**    * 获取某一个元素的角标    * 如果只出现一次,就返回一个数字,如果大于一次,就返回数组    */   this.indexOf = function(obj){     var rstArr = [];     var count = 0;     for(var i = 0 ;i < length ;i++){        if(obj == arr[i]){            rstArr[count++] = i;        }     }     if(count == 1){        return rstArr[0];     }     return rstArr;   }       this.toString = function(){    return arr.toString();     }}  //测试代码var list = new ArrayList();list.add('张三');list.add('李四');list.add('王五');list.add('赵六');list.add('王五');console.log(list.size());console.log(list.toString());console.log(list.contains('张三'));list.remove('王五',true); //null,undefined,''console.log(list.toString());console.log(list.get(0));console.log(list.get(1));console.log(list.get(2));console.log(list.size());  console.log(list.toArray());list.add('张三');list.add('张三');console.log(list.toArray());console.log(list.indexOf('张三'));console.log(list.indexOf('赵六'));运行结果:到此这篇关于JavaScript常用方法和封装详情的文章就介绍到这了转载自https://www.jb51.net/article/242112.htm
  • [技术干货] python中的getter与setter
    因为java开发的习惯,想要在python开发中使用类似JavaBean的结构。在python可以直接结合java中的编写习惯编写getter和setter方法class  DataBean:    """bean类"""    def __init__(self):        """构造方法"""        self.username: str = ""        self.password: str = ""    def set_username(self, username: str):        """设置用户名"""        self.username = username    def set_password(self, password: str):        """设置密码"""        self.password = password    def get_username(self):        """获取用户名"""        return self.username    def get_password(self):        """"获取密码"""        return self.password这是结合java的习惯与python类的使用写出的getter和setter结构,当然也可以完全按照java中的写法class  DataBean:    """bean类"""    # 用户名    username: str = ""    # 密码    password: str = ""    def set_username(self, username: str):        """设置用户名"""        self.username = username    def set_password(self, password: str):        """设置密码"""        self.password = password    def get_username(self):        """获取用户名"""        return self.username    def get_password(self):        """"获取密码"""        return self.password使用python的装饰器在python内置的装饰器中,@property和@XXX.setter是针对于getter和setter方法的不二之选。当一个方法(函数)的最终目的是返回一个值时,可以@property装饰该方法(因为java的使用习惯,我更想称之为注解),这样就可以达成getter方法。当在一个方法的上方使用XXX.setter装饰时,代表可以直接通过类实例对象名称.变量名为其变量赋值,其中XXX代表变量名同时也是方法(函数)名称,具体可以看下方示例:class  DataBean:    """bean类"""    # 替代setter方法    @username.setter    def username(self, username: str):        """设置用户名"""        self.username = username    @password.setter    def password(self, password: str):        """设置密码"""        self.password = password    # 替代getter方法    @property    def username(self):        """获取用户名"""        return self.username    @property    def password(self):        """"获取密码"""        return self.password# 测试data_bean = DataBean()# 直接赋值date_bean.username = "123"print(data_bean.username)
  • [技术干货] AIDL 介绍
    前言在决定用这个标题之前甚是忐忑,主要是担心自己对AIDL的理解不够深入,到时候大家看了之后说——你这是什么玩意儿,就这么点东西就敢说够了?简直是坐井观天不知所谓——那样就很尴尬了。不过又转念一想,我辈年轻人自当有一种一往无前的锐气,标题大气一点岂不更好?并且大家都是文明人,总归更多的是理解与补充而不是侮辱与谩骂?所以最终还是厚颜用了这么一个不怎么有耻的标题。好了,接下来进入正题,谈谈我对AIDL的理解和认识。正文1,概述AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。是的,首先我们知道的第一点就是:AIDL是一种语言。既然是一种语言,那么相应的就很自然的衍生出了一些问题:为什么要设计出这么一门语言?它有哪些语法?我们应该如何使用它?再深入一点,我们可以思考,我们是如何通过它来达到我们的目的的?更深入一点,为什么要这么设计这门语言?会不会有更好的方式来实现我们的目的?接下来,我们就一步步的来解答上面的这些问题。ps:1,在研究AIDL相关的东西之前,一些必要的知识储备是要有的。一方面是关于Android中service相关的知识,要了解的比较通透才行,关于这方面的东西可以参考 Android中的Service:默默的奉献者 (1),Android中的Service:Binder,Messenger,AIDL(2) 这两篇博文。另一方面是关于Android中序列化的相关知识,这方面的东西文中会简单提及,但是如果想要深入的研究一下的话最好还是去找一些这方面的资料看一下。 2,我的编译环境为Android Studio2.1.2,SDK Version 23,JDK 1.7。2,为什么要设计这门语言?设计这门语言的目的是为了实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。每一个进程都有自己的Dalvik VM实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生。每个进程之间都你不知我,我不知你,就像是隔江相望的两座小岛一样,都在同一个世界里,但又各自有着自己的世界。而AIDL,就是两座小岛之间沟通的桥梁。相对于它们而言,我们就好像造物主一样,我们可以通过AIDL来制定一些规则,规定它们能进行哪些交流——比如,它们可以在我们制定的规则下传输一些特定规格的数据。总之,通过这门语言,我们可以愉快的在一个进程访问另一个进程的数据,甚至调用它的一些方法,当然,只能是特定的方法。但是,如果仅仅是要进行跨进程通信的话,其实我们还有其他的一些选择,比如 BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 占用的系统资源比较多,如果是频繁的跨进程通信的话显然是不可取的;Messenger 进行跨进程通信时请求队列是同步进行的,无法并发执行,在有些要求多进程的情况下不适用——这种时候就需要使用 AIDL 了。如果想要了解它们更详细的区别的话,可以去我的另一篇博文看看:Android中的Service:Binder,Messenger,AIDL(2)3,它有哪些语法?其实AIDL这门语言非常的简单,基本上它的语法和 Java 是一样的,只是在一些细微处有些许差别——毕竟它只是被创造出来简化Android程序员工作的,太复杂不好——所以在这里我就着重的说一下它和 Java 不一样的地方。主要有下面这些点:文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。数据类型:AIDL默认支持一些数据类型,在使用这些数据类型的时候是不需要导包的,但是除了这些类型之外的数据类型,在使用之前必须导包,就算目标文件与当前正在编写的 .aidl 文件在同一个包下——在 Java 中,这种情况是不需要导包的。比如,现在我们编写了两个文件,一个叫做 Book.java ,另一个叫做 BookManager.aidl,它们都在 com.lypeer.aidldemo 包下 ,现在我们需要在 .aidl 文件里使用 Book 对象,那么我们就必须在 .aidl 文件里面写上 import com.lypeer.aidldemo.Book; 哪怕 .java 文件和 .aidl 文件就在一个包下。默认支持的数据类型包括:Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。String 类型。CharSequence类型。List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。定向tag:这是一个极易被忽略的点——这里的“被忽略”指的不是大家都不知道,而是很少人会正确的使用它。在我的理解里,定向 tag 是这样的:AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。其中,数据流向是针对在客户端中的那个传入方法的对象而言的。in 为定向 tag 的话表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动;out 的话表现为服务端将会接收到那个对象的的空对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动;inout 为定向 tag 的情况下,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。具体的分析大家可以移步我的另一篇博文:你真的理解AIDL中的in,out,inout么?另外,Java 中的基本类型和 String ,CharSequence 的定向 tag 默认且只能是 in 。还有,请注意,请不要滥用定向 tag ,而是要根据需要选取合适的——要是不管三七二十一,全都一上来就用 inout ,等工程大了系统的开销就会大很多——因为排列整理参数的开销是很昂贵的。两种AIDL文件:在我的理解里,所有的AIDL文件大致可以分为两类。一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。一类是用来定义方法接口,以供系统使用来完成跨进程通信的。可以看到,两类文件都是在“定义”些什么,而不涉及具体的实现,这就是为什么它叫做“Android接口定义语言”。注:所有的非默认支持数据类型必须通过第一类AIDL文件定义才能被使用。
  • [区域初赛赛题问题] 【Java语言】本地build_and_run运行没有问题,提交之后显示选手程序运行失败
    【功能模块】本地build_and_run运行没有问题,提交之后显示选手程序运行失败希望能查一下什么原因团队 不会取名,用户命 hw035830719提交语言 java最近一次提交时间:2022-03-20 15:25:22【操作步骤&问题现象】1、Java语言,本地build_and_run运行没有问题2、提交显示选手程序运行失败【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [区域初赛赛题问题] Java里面可以定义多个类吗
    Java里面可以定义多个类吗
  • [常见FAQ] [java]代码一直分配方案不合法,没有找到解决方案
    【功能模块】java写的代码一直显示代码分配方案不合法,想看一下后台的具体是哪一条报这个原因。【操作步骤&问题现象】选手程序输出的解决方案不满足要求,可能的问题包括:− 输出文件格式有误,未遵循输出说明要求格式导致判题器解析失败。如: 有空行;应该是 0 或正整数的位置却填充了其它非法字符; 输出文件中包含中文等。− 存在客户节点的带宽需求分配到不满足 QoS 约束的边缘节点。− 未对所有时刻的带宽需求进行分配。− 存在某个时刻,有客户节点带宽需求分配不正确。如:未完全分配、多分配。− 边缘节 点或者客户 节点不是来自输入的数 据集。− 超出边缘节点的带宽上限。【截图信息】【日志信息】(可选,上传日志内容或者附件)分配方案不合法
  • [java] Java有了synchronized,为什么还要提供Lock
    本文分享自华为云社区《[Java中提供了synchronized,为什么还要提供Lock呢?](https://bbs.huaweicloud.com/blogs/336889?utm_source=zhihu&utm_medium=bbs-ex&utm_campaign=other&utm_content=content)》,作者: 冰 河。 在Java中提供了synchronized关键字来保证只有一个线程能够访问同步代码块。既然已经提供了synchronized关键字,那为何在Java的SDK包中,还会提供Lock接口呢?这是不是重复造轮子,多此一举呢?今天,我们就一起来探讨下这个问题。 # 再造轮子? 既然JVM中提供了synchronized关键字来保证只有一个线程能够访问同步代码块,为何还要提供Lock接口呢?这是在重复造轮子吗?Java的设计者们为何要这样做呢?让我们一起带着疑问往下看。 # 为何提供Lock接口? 很多小伙伴可能会听说过,在Java 1.5版本中,synchronized的性能不如Lock,但在Java 1.6版本之后,synchronized做了很多优化,性能提升了不少。那既然synchronized关键字的性能已经提升了,那为何还要使用Lock呢? 如果我们向更深层次思考的话,就不难想到了:我们使用synchronized加锁是无法主动释放锁的,这就会涉及到死锁的问题。 # 死锁问题 如果要发生死锁,则必须存在以下四个必要条件,四者缺一不可。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/18/1647586293676911967.png) - **互斥条件** 在一段时间内某资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待。 - **不可剥夺条件** 线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己来释放(只能是主动释放)。 - **请求与保持条件** 线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放。 - **循环等待条件** 在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。 # synchronized的局限性 如果我们的程序使用synchronized关键字发生了死锁时,synchronized关键是是无法破坏“不可剥夺”这个死锁的条件的。这是因为synchronized申请资源的时候, 如果申请不到, 线程直接进入阻塞状态了, 而线程进入阻塞状态, 啥都干不了, 也释放不了线程已经占有的资源。 然而,在大部分场景下,我们都是希望“不可剥夺”这个条件能够被破坏。也就是说对于“不可剥夺”这个条件,占用部分资源的线程进一步申请其他资源时, 如果申请不到, 可以主动释放它占有的资源, 这样不可剥夺这个条件就破坏掉了。 如果我们自己重新设计锁来解决synchronized的问题,我们该如何设计呢? # 解决问题 了解了synchronized的局限性之后,如果是让我们自己实现一把同步锁,我们该如何设计呢?也就是说,我们在设计锁的时候,要如何解决synchronized的局限性问题呢?这里,我觉得可以从三个方面来思考这个问题。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/18/1647586369240495968.png) (1)能够响应中断。 synchronized的问题是, 持有锁A后, 如果尝试获取锁B失败, 那么线程就进入阻塞状态, 一旦发生死锁, 就没有任何机会来唤醒阻塞的线程。 但如果阻塞状态的线程能够响应中断信号, 也就是说当我们给阻塞的线程发送中断信号的时候, 能够唤醒它, 那它就有机会释放曾经持有的锁A。 这样就破坏了不可剥夺条件了。 (2)支持超时。 如果线程在一段时间之内没有获取到锁, 不是进入阻塞状态, 而是返回一个错误, 那这个线程也有机会释放曾经持有的锁。 这样也能破坏不可剥夺条件。 (3)非阻塞地获取锁。 如果尝试获取锁失败, 并不进入阻塞状态, 而是直接返回, 那这个线程也有机会释放曾经持有的锁。 这样也能破坏不可剥夺条件。 体现在Lock接口上,就是Lock接口提供的三个方法,如下所示。 // 支持中断的API void lockInterruptibly() throws InterruptedException; // 支持超时的API boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 支持非阻塞获取锁的API boolean tryLock(); - lockInterruptibly() 支持中断。 - tryLock()方法 tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。 - tryLock(long time, TimeUnit unit)方法 tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。 也就是说,对于死锁问题,Lock能够破坏不可剥夺的条件,例如,我们下面的程序代码就破坏了死锁的不可剥夺的条件。 public class TansferAccount{ private Lock thisLock = new ReentrantLock(); private Lock targetLock = new ReentrantLock(); //账户的余额 private Integer balance; //转账操作 public void transfer(TansferAccount target, Integer transferMoney){ boolean isThisLock = thisLock.tryLock(); if(isThisLock){ try{ boolean isTargetLock = targetLock.tryLock(); if(isTargetLock){ try{ if(this.balance >= transferMoney){ this.balance -= transferMoney; target.balance += transferMoney; } }finally{ targetLock.unlock } } }finally{ thisLock.unlock(); } } } } 例外,Lock下面有一个ReentrantLock,而ReentrantLock支持公平锁和非公平锁。 在使用ReentrantLock的时候, ReentrantLock中有两个构造函数, 一个是无参构造函数, 一个是传入fair参数的构造函数。 fair参数代表的是锁的公平策略, 如果传入true就表示需要构造一个公平锁, 反之则表示要构造一个非公平锁。如下代码片段所示。 //无参构造函数: 默认非公平锁 public ReentrantLock() { sync = new NonfairSync(); } //根据公平策略参数创建锁 public ReentrantLock(boolean fair){ sync = fair ? new FairSync() : new NonfairSync(); } 锁的实现在本质上都对应着一个入口等待队列, 如果一个线程没有获得锁, 就会进入等待队列, 当有线程释放锁的时候, 就需要从等待队列中唤醒一个等待的线程。 如果是公平锁, 唤醒的策略就是谁等待的时间长, 就唤醒谁, 很公平; 如果是非公平锁, 则不提供这个公平保证, 有可能等待时间短的线程反而先被唤醒。 而Lock是支持公平锁的,synchronized不支持公平锁。 最后,值得注意的是,在使用Lock加锁时,一定要在finally{}代码块中释放锁,例如,下面的代码片段所示。 try{ lock.lock(); }finally{ lock.unlock(); } 注:其他synchronized和Lock的详细说明,小伙伴们自行查阅即可。
  • [区域初赛赛题问题] 【Java语言】本地build_and_run运行没有问题,提交之后显示选手程序运行失败
    【功能模块】本地build_and_run运行没有问题,提交之后显示选手程序运行失败希望能查一下什么原因。。。团队吾辈当自强,最近一次提交时间:2022-03-17 21:06:10【操作步骤&问题现象】1、Java语言,本地build_and_run运行没有问题2、提交显示选手程序运行失败【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [区域初赛赛题问题] java提交运行失败
    【功能模块】本地提交没问题,提交后一直显示 运行失败【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)CodeCraft-2022.zip00查看问题2022-03-17 11:31:58
  • [区域初赛赛题问题] java多次提示打开选手文件失败
    5. 打开选手输出文件失败未输出结果文件、输出文件位置不正确或者输出文件中包含中文等导致的编解码失败。在本地能正常输出文件,也无中文字符,怀疑是输出位置有误,应该输出到那个目录呢。
  • [区域初赛赛题问题] java语言提交显示程序编译异常
    请问Java提交压缩包需要提交哪些内容
  • [区域初赛赛题问题] java本地编译运行正确,上传程序运行失败,希望能查一下后台报错
    【功能模块】java在本地虚拟机上(系统为ubuntu18.04)编译运行没问题,上传后提示选手程序运行失败【操作步骤&问题现象】【截图信息】【日志信息】(可选,上传日志内容或者附件)
总条数:2301 到第 页
上滑加载中