这个问题困扰了我一段时间,但我还没有找到完整的答案(例如,这个是C#在try/finally之外或之内初始化一次性资源).考虑以下两个Java代码片段:
Closeable in = new FileInputStream("data.txt");
try {
doSomething(in);
} finally {
in.close();
}
Run Code Online (Sandbox Code Playgroud)
和第二种变化
Closeable in = null;
try {
in = new FileInputStream("data.txt");
doSomething(in);
} finally {
if (null != in) in.close();
}
Run Code Online (Sandbox Code Playgroud)
令我担心的部分是线程可能在获取资源的时刻(例如文件被打开)之间有些中断,但结果值未分配给相应的局部变量.是否还有其他情况,线程可能会在上述点之外被中断,除了:
我已经读到第二种方法有点"惯用",但IMO在上面的场景中没有区别,在所有其他场景中它们都是平等的.
所以问题是:
两者有什么不同?如果我担心释放资源(特别是在多线程应用程序中),我应该更喜欢哪个?为什么?
如果有人指出我支持答案的Java/JVM规范的部分,我将不胜感激.
我写了七个测试用例来理解finally块的行为.如何finally运作背后的逻辑是什么?
package core;
public class Test {
public static void main(String[] args) {
new Test().testFinally();
}
public void testFinally() {
System.out.println("One = " + tryOne());
System.out.println("Two = " + tryTwo());
System.out.println("Three = " + tryThree());
System.out.println("Four = " + tryFour());
System.out.println("Five = " + tryFive());
System.out.println("Six = " + trySix());
System.out.println("Seven = " + trySeven());
}
protected StringBuilder tryOne() {
StringBuilder builder = new StringBuilder();
try {
builder.append("Cool");
return builder.append("Return");
}
finally {
builder = null; …Run Code Online (Sandbox Code Playgroud) 如果没有抛出异常,我有一些我想要执行的代码.
目前我这样做:
try:
return type, self.message_handlers[type](self, length - 1)
finally:
if not any(self.exc_info()):
self.last_recv_time = time.time()
Run Code Online (Sandbox Code Playgroud)
这可以改进吗?这是最好的方法吗?
如果控制流出try子句的末尾,则执行可选的else子句.
目前,除了异常或执行return,continue或break语句之外,控制"流出结束".
大多数时候,我唯一看到的块块就是这样的东西
FileInputStream f;
try{
f= new FileInputStream("sample.txt");
//something that uses f and sometimes throws an exception
}
catch(IOException ex){
/* Handle it somehow */
}
finally{
f.close();
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果f的范围以封闭块结束,为什么我们需要在finally中关闭它?
try或catch块被中断时finally块是什么时候不执行的?doc说"如果执行try或catch代码的线程被中断或终止,即使整个应用程序继续执行,finally块也可能无法执行".有人能举例说明这种情况吗?
我读过的所有内容声称线程中止将在从ThreadAbortException结束之前执行finally块.我想确认这一点,以便我可以计划如何处理可以无限期挂起的某些第三方代码.但是下面的测试让我感到困惑:
public void runTest(DateTime deadline)
{
testThread = new Thread(() =>
{
try
{
Console.WriteLine("test thread started at " + DateTime.Now.ToShortTimeString());
while (true) { }
}
finally
{
Console.WriteLine("test thread entered FINALLY at " + DateTime.Now.ToShortTimeString());
while (true) { }
}
});
testThread.Start();
while (testThread.IsAlive && deadline.Subtract(DateTime.Now).TotalSeconds > 0)
{
Console.WriteLine("main thread while loop " + DateTime.Now.ToShortTimeString());
Thread.Sleep(10000);
}
if (testThread.IsAlive)
testThread.Abort();
Console.WriteLine("main thread after abort call " + DateTime.Now.ToShortTimeString());
}
Run Code Online (Sandbox Code Playgroud)
我在运行时发现的是控制台从未提到进入finally块.应用程序在.abort调用之后继续,好像根本没有finally块.难道我做错了什么?在到达最终写入控制台之前,不应该控制传递给finally块,还是执行顺序仍然是最终在单独的线程中的事实的函数?
到目前为止,C++(不幸的是)不支持finally语句的子句try.这导致了对如何释放资源的猜测.在互联网上研究了这个问题之后,虽然我找到了一些解决方案,但我并没有明白他们的表现(如果表现并不重要,我会使用Java).所以我不得不做基准测试.
选项是:
CodeProjectfinally提出的基于Functor的类.它很强大,但很慢.并且反汇编表明外部函数局部变量被非常低效地捕获:逐个推送到堆栈,而不是仅仅将帧指针传递给内部(lambda)函数.
RAII:堆栈上的手动清洁器对象:缺点是手动键入并为每个使用的位置定制它.另一个缺点是需要将资源释放所需的所有变量复制到其中.
MSVC++特定__try/ __finally声明.缺点是它显然不便携.
我创建了这个小基准来比较这些方法的运行时性能:
#include <chrono>
#include <functional>
#include <cstdio>
class Finally1 {
std::function<void(void)> _functor;
public:
Finally1(const std::function<void(void)> &functor) : _functor(functor) {}
~Finally1() {
_functor();
}
};
void BenchmarkFunctor() {
volatile int64_t var = 0;
const int64_t nIterations = 234567890;
auto start = std::chrono::high_resolution_clock::now();
for (int64_t i = 0; i < nIterations; i++) {
Finally1 doFinally([&] {
var++;
});
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
double …Run Code Online (Sandbox Code Playgroud) 我正在LongAdder详细分析算法。LongAdder扩展类Striped64,在该类中,基本方法是retryUpdate. 以下代码取自该方法;在链接的源代码中,它占据了第 212-222 行:
try { // Recheck under lock
Cell[] rs; int m, j;
if ( (rs = cells) != null &&
(m = rs.length) > 0 &&
rs[j = (m - 1) & h] == null) {
rs[j] = r;
created = true;
}
} finally {
busy = 0;
}
Run Code Online (Sandbox Code Playgroud)
问题:这个try块怎么会失败?
注意数组访问
rs[j = (m - 1) & h]
Run Code Online (Sandbox Code Playgroud)
不应该抛出 anIndexOutOfBoundsException因为按位与运算的结果总是小于或等于其整数参数的最小值,因此 0 <= j …
在以前的 Angular 版本中,我使用的finally()就像下面的代码一样
constructor(
private http: Http
) { }
const headers = new Headers({ 'Authorization': this.authenticate.getToken(), 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers: headers });
return this.http.put(Globals.SERVER_URL + '/alert/exempted?_id=' + alertId + '&isExempted=' + status + '&app_id=' + app_id, options )
.map(this.extractData)
.catch(this.handleError)
.finally(() => {
this.exceptionSubject.next();
});
Run Code Online (Sandbox Code Playgroud)
但是现在使用 Angular 7 时,我不能再使用它了。如何在代码中插入finally(HttpClient)?这是我现有的代码:
constructor(
private http: HttpClient
) { }
const header = new HttpHeaders({'Content-Type': 'application/json'});
return this.http.get(Globals.ATTENDANCE_URL + '/individual_employment_setting/detail/' + id, { headers: header }) …Run Code Online (Sandbox Code Playgroud) 我正在从 Java 语言规范中考虑这一点:
如果 catch 块由于原因 R 突然完成,则执行 finally 块。然后有一个选择:
如果 finally 块正常完成,则 try 语句由于原因 R 突然完成。
如果 finally 块因原因 S 突然完成,则 try 语句因原因 S 突然完成(并且原因 R 被丢弃)。
我有一个块如下:
try {
.. do stuff that might throw RuntimeException ...
} finally {
try {
.. finally block stuff that might throw RuntimeException ...
} catch {
// what to do here???
}
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,我希望块中的任何RuntimeException抛出finally都能逃脱,前提是它不会导致RuntimeException主try块中的抛出被丢弃。
Java 中有什么方法可以让我知道与块关联的finally块是否正常完成?
我猜我可以将 a …
finally ×10
java ×6
try-catch ×4
exception ×3
abort ×1
algorithm ×1
angular ×1
angular-http ×1
c# ×1
c++ ×1
httpclient ×1
performance ×1
python ×1
python-3.x ×1
raii ×1
resources ×1
try-finally ×1