try-catch-finally的执行顺序
来源:互联网 发布:数据挖掘技术有哪些 编辑:程序博客网 时间:2024/06/04 22:25
try-catch-finally的执行顺序
简化的例子
try-catch-finally中finally块中的代码会在try块中的return语句前执行,现在考虑在try和finally中对同一变量进行值修改的情况,代码如下:
public class TempMain { public static int id =0; public static void main(String[] args){ System.out.println("返回:"+changeid()); System.out.println("最终id:"+id); } public static int changeid() { try { id = 1; return id; } catch (Exception e) { return id; } finally { id =2; } }}
执行结果为
返回:1最终id:2
可见,虽然在函数返回结果前,finally块中的代码将id的值修改为了2,但函数的返回结果未受影响,仍然返回了1。
用javap查看这段代码的字节码,得到:
其中 Locals = 3 表示本地变量的slot个数(编号0-2)
可以看到,虽然有将静态变量id赋值为2的操作,但真正返回的是在执行finally块之前就存在第三个slot中的“1”。
将代码简单更改,在finally中也添加return语句
public class TempMain { public static int id =0; public static void main(String[] args){ System.out.println("返回:"+changeid()); System.out.println("最终id:"+id); } public static int changeid() { try { id = 1; return id; } catch (Exception e) { return id; } finally { id =2; return id; } }}
执行结果为
返回:2最终id:2
来看看这次生成的字节码
这一次,由于finally中含有return语句,因此直接将静态变量id的最新值返回给了调用方。
并发的例子
前面简化的例子,证明了return语句最好写在try中,除非你确实想在finally中对返回结果再进行修改。来看看try-catch-finally对并发结果的影响。
public class TempMain { public static int id =0; static ReentrantLock lock = new ReentrantLock(); public static void main(String[] args){ Thread thread1 = new Thread(new Runnable(){ @Override public void run() { System.out.println("T1 return "+changeid(1)); }}); Thread thread2 = new Thread(new Runnable(){ @Override public void run() { System.out.println("T2 return "+changeid(2)); }}); thread1.start(); thread2.start(); } @SuppressWarnings("finally") public static int changeid(int nid){ lock.lock(); try{ id = nid ; }catch(Exception e){ return id; }finally{ lock.unlock(); if(nid==1){ try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } return id; } } }
这段代码中,两个线程调用了同一个函数,该函数会修改静态变量id的值,并且如果是线程1调用的话,会sleep 5秒。按照期望,线程1将得到返回值1,线程2将得到返回值2,但运行的结果:
T2 return 2T1 return 2
原因是,将return语句写在了finally中,此时,先执行的线程1已经放弃了锁,但由于需要sleep 5秒,因此并没有返回结果。但这时线程2得到了锁并修改了id的值,之后,线程1 sleep结束,返回结果。还记得前面例子中第二段代码么?返回的不是slot中的值,而是反回了getstatic的值,也就是id的值。因此,线程1的返回值是id的最新值—2。
为了避免这种由于过早释放锁导致返回结果被修改的情况,办法就是保持将return写在try中的习惯
public class TempMain { public static int id =0; static ReentrantLock lock = new ReentrantLock(); public static void main(String[] args){ Thread thread1 = new Thread(new Runnable(){ @Override public void run() { System.out.println("T1 return "+changeid(1)); }}); Thread thread2 = new Thread(new Runnable(){ @Override public void run() { System.out.println("T2 return "+changeid(2)); }}); thread1.start(); thread2.start(); } @SuppressWarnings("finally") public static int changeid(int nid){ lock.lock(); try{ id = nid ; return id; }catch(Exception e){ return id; }finally{ lock.unlock(); if(nid==1){ try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
这一次得到正确的结果,因为线程1返回的是存在slot(本地变量)中的值。
T2 return 2T1 return 1
- try, catch, finally, return的执行顺序
- try、catch、finally、return的执行顺序
- try、catch、finally、return的执行顺序
- try catch finally return 的执行顺序
- try、catch、finally、return的执行顺序
- Java try catch finally的执行顺序
- try catch finally return 的执行顺序
- try、catch、finally的执行顺序
- try catch finally 的执行顺序
- Java try catch finally的执行顺序
- Java try catch finally的执行顺序
- Java try catch finally的执行顺序
- try catch finally return 的执行顺序
- try catch finally的执行顺序
- Java try catch finally的执行顺序
- try catch finally的执行顺序
- try-catch-finally的执行顺序
- try-catch-finally-return的执行顺序
- 处理乘法取模爆long long 的方法
- POJ 3907 Build Your Home
- Android学习心得(10) --- MAC下Android反编译(2)
- AngularJS Tutorial(12)from w3school
- 积累linux常用的命令
- try-catch-finally的执行顺序
- hihoCoder 1122 二分图二•二分图最大匹配之匈牙利算法
- java实现文件的上传下载
- Mahone的CTS研究笔记(一):什么是CTS
- C的变长参数
- 指针函数与函数指针的区别
- 优秀代码风格
- UIEvent
- 基本固件框架的追踪研读之SETUP命令的处理7