当前位置: 首页 > 后端技术 > Java

不寻常的Java:StackTrace扩展了Throwable

时间:2023-04-02 00:00:39 Java

在Java中,您可以做很少见的事情,通常是因为它没有用。但是,Java中有一些非常有用的不寻常的东西。ChronicleSoftware在其低级库中使用了许多不同的通用模式,大多数开发人员通常不会遇到这些模式。其中之一是扩展Throwable但不是错误或异常的类。StackTrace展开了ThrowablepublicclassEgMain{staticclassMyCloseableimplementsCloseable{protectedtransientvolatileStackTraceclosedHere;@Overridepublicvoidclose(){closedHere=newStackTrace("Closedhere");//第13行}publicvoiduseThis(){if(closedHere!=null)thrownewIllegalStateException("Closed",closedHere);}}publicstaticvoidmain(String[]args)throwsInterruptedException{MyCloseablemc=newMyCloseable();//第27行Threadt=newThread(mc::close,"closer");t.开始();t.join();mc.useThis();}}一些重要的旁注是的,我确实在我的IDE比例字体中使用了它。我在Windows上使用Verdana,很容易就习惯了,不想回头了。这不是我期望被抛出的课程。检查直接扩展Throwable的类,例如Exception,这样编译器会帮助您做到这一点。Throwable的堆栈跟踪是在创建Throwable时确定的,而不是它被抛出的位置。通常,这是同一条线,但不一定如此。您不必抛出Throwable来获取堆栈跟踪。堆栈跟踪元素对象在需要时创建。相反,将元数据添加到对象本身以减少开销,并在首次使用时填充StackTraceElements数组。但是让我们更详细地看一下这个类。该类将记录创建它的位置和创建它的线程的堆栈跟踪。稍后您应该会看到这有何用处。它还可用于保存另一个正在运行的线程的堆栈跟踪。另一个线程的堆栈跟踪只有在线程到达安全点时才会获取,这可能是您尝试获取它之后的某个时间。这是由于JVM停止了线程,通常JVM等待停止每个线程,因此它可以检查您试图捕获的线程的堆栈。也就是说,它的开销很高,但非常有用。StackTrace作为一个延迟异常我们不想抛出这个Throwable,但是它可以记录后面可能抛出的异常的原因。为什么资源被关闭publicclassCreatedMain{staticclassMyResourceimplementsCloseable{privatefinaltransientStackTracecreatedHere=newStackTrace("Createdhere");volatiletransientbooleanclosed;@Overridepublicvoidclose()throwsIOException{closed=true;}@覆盖受保护的voidfinalize()throwsThrowable{super.finalize();if(!closed)Logger.getAnonymousLogger().log(Level.WARNING,"资源已丢弃但未关闭",createdHere);}}publicstaticvoidmain(String[]args)throwsInterruptedException{NewMyResource();//第27行System.gc();线程.睡眠(1000);尝试使用已关闭资源的位置,但这并不能告诉您为什么它在没有其他信息的情况下被关闭。由于StackTrace是可抛出的,您可以将其用作后续异常或错误的原因。您可以看到关闭资源的线程,所以您知道它发生在另一个线程中,并且您可以看到它关闭原因的堆栈跟踪。这有助于快速诊断过早关闭资源的难以发现的问题。哪个资源被丢弃了?长期存在的Closeable对象可能具有复杂的生命周期,确保它们在需要时关闭可能难以跟踪并可能导致资源泄漏。有些资源在GC释放对象的时候并没有被清理掉,比如RandomAccessFile对象在GC上被清理掉了,它代表的文件除非你关闭它,否则不会被关闭,从而导致潜在的文件句柄资源泄漏。公共类JitteryMain实现Runnable{volatilelongloopStartMS=Long.MIN_VALUE;易失性布尔值运行=真;@Overridepublicvoidrun(){while(running){loopStartMS=System.currentTimeMillis();做工作();loopStartMS=Long.MIN_VALUE;}}privatevoiddoWork(){intloops=newRandom().nextInt(100);for(inti=0;i100){logger.getAnonymouslogger().log(level.info,“线程”的花费比这里预期的时间更长,是“+busyms+”ms,任何想法在这种情况下发生的任何想法。是Thread.sleep(time)休眠时间最短,而不是最长,并且在Windows上休眠1毫秒实际上需要大约1.9毫秒。检测单线程序资源何时在线程序间并发布访问packagenet.openhft.chronicle.core;publicclassConcurrentUsageMain{staticclassSingleThreadedResource{privateStackTraceusedHere;私有线程usedByThread;publicvoiduse(){checkMultithreadedAccess();//BLAH}privatevoidcheckMultithreadedAccess(){if(usedHere==null||usedByThread==null){usedHere=newStackTrace("第一次在这里使用");usedByThread=Thread.currentThread();}elseif(Thread.currentThread()!=usedByThread){thrownewIllegalStateException("使用了两个线程"+Thread.currentThread()+"and"+usedByThread,usedHere);}}}publicstaticvoidmain(String[]args)throwsInterruptedException{SingleThreadedResourcestr=newSingleThreadedResource();finalThreadthread=newThread(()->str.use(),"资源user");//line25thread.start();thread.join();str.use();//line29}}打印如下:你可以看到资源已经被两个线程和它们的线程使用了names但是,您还可以看到它们在堆栈中的位置以确定可能的原因。关闭此跟踪会创建一个StackTrace,它对线程和可能的JVM有重大影响。但是,很容易将其关闭并替换使用控制标志(例如系统属性)为null。使用null不需要太多特殊处理,因为记录器会忽略为null的Throwable,并且您可以为Exception提供一个null原因,这与不提供一个原因相同。结论虽然有一个直接扩展ThrowableSurprising的类,但它是允许的,并且对于提供有关资源生命周期的附加信息或添加可以在生产中运行的简单监控也非常有用。如果本文对您有帮助,请不要别忘了给我一个3链接,点赞,转发,评论,下期见。收藏等于卖淫,喜欢才是真理。了解更多JAVA知识技能,关注和私信博主